Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix bug that undefined internal is a warning only for -pedantic-errors #98016

Merged
merged 12 commits into from
Jul 11, 2024

Conversation

ccrownhill
Copy link
Contributor

This fixes issue #39558 which mentions the problem when compiling the following code with -pedantic-errors flag (it also mentions -Wall -Wextra but those shouldn't change the output, which is also the case in GCC):

static void f();

int main()
{
    f;
}

Clang only outputs an undefined-internal warning on the first line, but according to 6.9/3

"... Moreover, if an identifier declared with internal linkage is used in an
 expression (other than as a part of the operand of a sizeof or _Alignof
 operator whose result is an integer constant), there shall be exactly one
 external definition for the identifier in the translation unit."

this should be illegal and hence an error.

I fixed this by changing the warning type from Warning to ExtWarn and by adding a suitable test.

Copy link

github-actions bot commented Jul 8, 2024

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 8, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 8, 2024

@llvm/pr-subscribers-clang

Author: Constantin Kronbichler (ccrownhill)

Changes

This fixes issue #39558 which mentions the problem when compiling the following code with -pedantic-errors flag (it also mentions -Wall -Wextra but those shouldn't change the output, which is also the case in GCC):

static void f();

int main()
{
    f;
}

Clang only outputs an undefined-internal warning on the first line, but according to 6.9/3

"... Moreover, if an identifier declared with internal linkage is used in an
 expression (other than as a part of the operand of a sizeof or _Alignof
 operator whose result is an integer constant), there shall be exactly one
 external definition for the identifier in the translation unit."

this should be illegal and hence an error.

I fixed this by changing the warning type from Warning to ExtWarn and by adding a suitable test.


Full diff: https://github.com/llvm/llvm-project/pull/98016.diff

2 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+1-1)
  • (added) clang/test/Sema/undefined_internal.c (+11)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 44fd51ec9abc9..ae3dbedd01693 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6013,7 +6013,7 @@ def note_deleted_assign_field : Note<
   "because field %2 is of %select{reference|const-qualified}4 type %3">;
 
 // These should be errors.
-def warn_undefined_internal : Warning<
+def warn_undefined_internal : ExtWarn<
   "%select{function|variable}0 %q1 has internal linkage but is not defined">,
   InGroup<DiagGroup<"undefined-internal">>;
 def err_undefined_internal_type : Error<
diff --git a/clang/test/Sema/undefined_internal.c b/clang/test/Sema/undefined_internal.c
new file mode 100644
index 0000000000000..1b6c3a4b76e05
--- /dev/null
+++ b/clang/test/Sema/undefined_internal.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -pedantic-errors
+
+static void f(void); // expected-error {{function 'f' has internal linkage but is not defined}}
+
+int main(void)
+{
+    f;
+    // expected-note@-1 {{used here}}
+    // expected-warning@-2 {{expression result unused}}
+}
+

Copy link
Member

@Sirraide Sirraide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix!

The changes LGTM, but you should also add a release note about this (in clang/docs/ReleaseNotes.rst, probably in the ‘Improvements to Clang’s Diagnostics’ section).

@ccrownhill
Copy link
Contributor Author

Ok I just added a commit with the addition to clang/docs/ReleaseNotes.rst.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this! C23 changed the normative wording here somewhat, so I think we should add additional test coverage. Specifically:

Moreover, if an identifier declared with internal linkage is used in an expression
there shall be exactly one external definition for the identifier in the translation unit, unless it is:
— part of the operand of a sizeof operator whose result is an integer constant;
— part of the operand of an alignof operator whose result is an integer constant;
— part of the controlling expression of a generic selection;
— part of the expression in a generic association that is not the result expression of its generic
selection;
— or, part of the operand of any typeof operator whose result is not a variably modified type.

How about adding those bullets as test cases to make sure we don't diagnose them?

@ccrownhill
Copy link
Contributor Author

ccrownhill commented Jul 10, 2024

That sounds good. I will have a look at that later today.

@ccrownhill
Copy link
Contributor Author

I added three more tests covering these points:
— part of the operand of a sizeof operator whose result is an integer constant;
— part of the controlling expression of a generic selection;
— or, part of the operand of any typeof operator whose result is not a variably modified type.

I did not see how to add tests for the following since they require just a type which I thought to be possible to achieve
with an undefined internal since for a type the first declaration is the definition, e.g. with typedef.
— part of the operand of an alignof operator whose result is an integer constant;
— part of the expression in a generic association that is not the result expression of its generic
selection; (this one is also a type since the association map contains only pairs of type names and result expressions)

Is there a way to test undefined internals for these cases?

@AaronBallman
Copy link
Collaborator

AaronBallman commented Jul 10, 2024

I did not see how to add tests for the following since they require just a type which I thought to be possible to achieve with an undefined internal since for a type the first declaration is the definition, e.g. with typedef.
— part of the operand of an alignof operator whose result is an integer constant;
— part of the expression in a generic association that is not the result expression of its generic selection; (this one is also a type since the association map contains only pairs of type names and result expressions)

Is there a way to test undefined internals for these cases?

What I had in mind for those was:

static void f();
int i = _Alignof(f);
int j = _Generic(&f, void (*)(void) : 1, default : 0); // okay
void *k = _Generic(&f, void (*)(void) : f, default : 0); // Not okay

https://godbolt.org/z/b1GfqPE61

@ccrownhill
Copy link
Contributor Author

Ah I see. Thank you for the suggestions!
I also tried the same for _Alignof but was put off by the errors generated by the -pedantic-errors flag.
But I guess I can just check that I don't get the undefined-internal error.

For the other two I had something similar but that still misses this point:
— part of the expression in a generic association that is not the result expression of its generic
selection
But that might also be because I don't understand this point well enough. I don't see which expression is there that is not the controlling expression and not a result expression.

Also, I was thinking that it would be best to group all tests into one file since they all test just one feature.
What do you think of that?

@ccrownhill
Copy link
Contributor Author

Since one error message will occlude others I had to split the files as I did in the latest commit.
I have added one for the _Alignof case checking for the errors I was getting in godbolt while also checking that no undefined-internal error occurred.
Lastly, I added the one illegal use case of _Generic from @AaronBallman 's suggestions.
I think this should cover everything.
What do you think?

@AaronBallman
Copy link
Collaborator

For the other two I had something similar but that still misses this point:
— part of the expression in a generic association that is not the result expression of its generic
selection
But that might also be because I don't understand this point well enough. I don't see which expression is there that is not the controlling expression and not a result expression.

Given: _Generic(foo, bar : baz), foo is the controlling expression, bar is the generic association, and assuming foo is of type bar, then baz is the result expression of the generic selection.

@ccrownhill
Copy link
Contributor Author

Oh that makes sense so

static void f();
void *k = _Generic(&f, void (*)(void) : 0, default : f);

should be ok since it is not in the result expression?

@ccrownhill
Copy link
Contributor Author

Sorry, my mistake. This doesn't work for default but the problem is that in this example

static void *f(void);
void *k = _Generic(&f, void *(*)(void) : 0, int (*)(void) : f());

the undefined-internal error is still raised even though it is not in the result expression anymore.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test cases should all be combined into a single file -- we don't stop issuing diagnostics after the first one, so it should be fine to put them all together into one file.

clang/docs/ReleaseNotes.rst Outdated Show resolved Hide resolved
clang/test/Sema/undefined-internal-basic.c Outdated Show resolved Hide resolved
clang/test/Sema/undefined-internal-alignof.c Outdated Show resolved Hide resolved
clang/test/Sema/undefined-internal-generic-selection.c Outdated Show resolved Hide resolved
clang/test/Sema/undefined-internal-sizeof.c Outdated Show resolved Hide resolved
clang/test/Sema/undefined-internal-sizeof.c Outdated Show resolved Hide resolved
clang/test/Sema/undefined-internal-typeof-c23.c Outdated Show resolved Hide resolved
@AaronBallman
Copy link
Collaborator

Oh that makes sense so

static void f();
void *k = _Generic(&f, void (*)(void) : 0, default : f);

should be ok since it is not in the result expression?

Correct, that's a good test case to add! Similarly, it would be good to add one like:

void *k = _Generic(&f, int (*)(void) : 0, default : f);

to show that it is diagnosed because it's used in the result expression.

@ccrownhill
Copy link
Contributor Author

Thank you very much for all the feedback:) I'll combine them into a file now.

@ccrownhill
Copy link
Contributor Author

Correct, that's a good test case to add!

The only problem is that currently, the behavior of Clang is incorrect for the case

static void *f(void);
void *k = _Generic(&f, void *(*)(void) : 0, default : f());

because it gives an error even though it should not.
But I can have a look into how to fix that.

@AaronBallman
Copy link
Collaborator

Correct, that's a good test case to add!

The only problem is that currently, the behavior of Clang is incorrect for the case

static void *f(void);
void *k = _Generic(&f, void *(*)(void) : 0, default : f());

because it gives an error even though it should not. But I can have a look into how to fix that.

If you look into it and it seems challenging to resolve, I think we can leave a FIXME comment next to the test case saying "this code is incorrectly rejected and should be accepted", file an issue in GitHub about it, and then land these changes because they're definitely an incremental improvement over what we have today.

@ccrownhill
Copy link
Contributor Author

If you look into it and it seems challenging to resolve, I think we can leave a FIXME comment next to the test case saying "this code is incorrectly rejected and should be accepted", file an issue in GitHub about it, and then land these changes because they're definitely an incremental improvement over what we have today.

Ok, I'll have a look after adding the above test cases.
Should I include the test that will break it for that already?

And also since the typeof test only works for C23 should I add it to the single test file and compile with -std=c23
or leave it in a separate test file?

@AaronBallman
Copy link
Collaborator

If you look into it and it seems challenging to resolve, I think we can leave a FIXME comment next to the test case saying "this code is incorrectly rejected and should be accepted", file an issue in GitHub about it, and then land these changes because they're definitely an incremental improvement over what we have today.

Ok, I'll have a look after adding the above test cases. Should I include the test that will break it for that already?

Yeah, go ahead and add the test, and add whatever // expected- comment to get the test to pass along with the FIXME comment.

And also since the typeof test only works for C23 should I add it to the single test file and compile with -std=c23 or leave it in a separate test file?

I'd probably spell it __typeof__ and leave the language standard unspecified, that's reasonable because it's a synonym for typeof.

@ccrownhill
Copy link
Contributor Author

ccrownhill commented Jul 11, 2024

Ok, that's done with the FIXME comment for now.
Maybe it is only because this is my first time contributing and I am not too familiar with the codebase but I couldn't see a trivial fix for the issue.
For now I think it's best to land these changes first.
I would just add an issue about it for now.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@AaronBallman
Copy link
Collaborator

I filed #98504 to track the remaining issue.

@AaronBallman AaronBallman merged commit e16882f into llvm:main Jul 11, 2024
4 of 5 checks passed
Copy link

@ccrownhill Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested
by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as
the builds can include changes from many authors. It is not uncommon for your
change to be included in a build that fails due to someone else's changes, or
infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself.
This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

@llvm-ci
Copy link
Collaborator

llvm-ci commented Jul 11, 2024

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-sie-ubuntu-fast running on sie-linux-worker while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/144/builds/2080

Here is the relevant piece of the build log for the reference:

Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: Sema/undefined-internal-basic.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/19/include -nostdsysteminc -fsyntax-only -verify /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c -Wno-pointer-arith -Wno-gnu-alignof-expression -Wno-unused -pedantic-errors
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/19/include -nostdsysteminc -fsyntax-only -verify /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c -Wno-pointer-arith -Wno-gnu-alignof-expression -Wno-unused -pedantic-errors
error: 'expected-error' diagnostics expected but not seen: 
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 3: function 'a' has internal linkage but is not defined
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 4: function 'b' has internal linkage but is not defined
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 5: function 'c' has internal linkage but is not defined
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 6: function 'd' has internal linkage but is not defined
error: 'expected-error' diagnostics seen but not expected: 
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 13: '_Alignof' is a C11 extension
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 15: '_Generic' is a C11 extension
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 17: '_Generic' is a C11 extension
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 22: '_Generic' is a C11 extension
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 24: '_Generic' is a C11 extension
error: 'expected-note' diagnostics expected but not seen: 
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 11: used here
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 17: used here
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 22: used here
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/undefined-internal-basic.c Line 24: used here
13 errors generated.

--

********************


@AaronBallman
Copy link
Collaborator

I've reverted the changes in 9f283bf because of the bot breakage. Oddly, I am seeing a different failure on Windows locally:

FAIL: Clang :: Sema/undefined-internal-basic.c (1 of 1)
******************** TEST 'Clang :: Sema/undefined-internal-basic.c' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
f:\source\llvm-project\llvm\out\build\x64-debug\bin\clang.exe -cc1 -internal-isystem F:\source\llvm-project\llvm\out\build\x64-Debug\lib\clang\19\include -nostdsysteminc -fsyntax-only -verify F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c -Wno-pointer-arith -Wno-gnu-alignof-expression -Wno-unused -pedantic-errors
# executed command: 'f:\source\llvm-project\llvm\out\build\x64-debug\bin\clang.exe' -cc1 -internal-isystem 'F:\source\llvm-project\llvm\out\build\x64-Debug\lib\clang\19\include' -nostdsysteminc -fsyntax-only -verify 'F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c' -Wno-pointer-arith -Wno-gnu-alignof-expression -Wno-unused -pedantic-errors
# .---command stderr------------
# | error: 'expected-error' diagnostics expected but not seen:
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 3: function 'a' has internal linkage but is not defined
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 4: function 'b' has internal linkage but is not defined
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 5: function 'c' has internal linkage but is not defined
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 6: function 'd' has internal linkage but is not defined
# | error: 'expected-warning' diagnostics seen but not expected:
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 3: function 'a' has internal linkage but is not defined
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 4: function 'b' has internal linkage but is not defined
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 5: function 'c' has internal linkage but is not defined
# |   File F:\source\llvm-project\clang\test\Sema\undefined-internal-basic.c Line 6: function 'd' has internal linkage but is not defined
# | 8 errors generated.
# `-----------------------------
# error: command failed with exit status: 1

--

********************
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
********************
Failed Tests (1):
  Clang :: Sema/undefined-internal-basic.c

so something has gone amiss...

@AaronBallman
Copy link
Collaborator

Okay, the Windows issue seems to have gone away with a full rebuild, which makes way more sense to me. :-) So I think it's just the llvm-clang-x86_64-sie-ubuntu-fast issue that needs to be resolved.

@AaronBallman
Copy link
Collaborator

I think adding -std=c11 to the RUN line should help; it at least removes the "is a C11 extension" diagnostics. (I guess this builder isn't defaulting to C17 for some reason?)

@AaronBallman
Copy link
Collaborator

I've relanded the changes with a fix here in commit 0171e23, hopefully that sticks!

@AaronBallman
Copy link
Collaborator

Yup, that resolved the issue: https://lab.llvm.org/buildbot/#/builders/144/builds/2082 -- not certain why that builder has a different default value for -std though. Clang defaults to C17, but that builder seems to be defaulting to C99.

@dyung
Copy link
Collaborator

dyung commented Jul 11, 2024

Yup, that resolved the issue: https://lab.llvm.org/buildbot/#/builders/144/builds/2082 -- not certain why that builder has a different default value for -std though. Clang defaults to C17, but that builder seems to be defaulting to C99.

This bot targets the PS4 which has kept an older version of the standard as the default for compatibility reasons.

@AaronBallman
Copy link
Collaborator

Yup, that resolved the issue: https://lab.llvm.org/buildbot/#/builders/144/builds/2082 -- not certain why that builder has a different default value for -std though. Clang defaults to C17, but that builder seems to be defaulting to C99.

This bot targets the PS4 which has kept an older version of the standard as the default for compatibility reasons.

Ahhhhh! I remembered that the PS used older versions of the standard, but I didn't realize that was this bot. "SIE" -- Sony Interactive Entertainment... now I get it. Thank you! :-)

@ccrownhill
Copy link
Contributor Author

Thank you very much for fixing that:)

@AaronBallman
Copy link
Collaborator

Thank you very much for fixing that:)

Happy to help, thank you for your contribution!

aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
llvm#98016)

This fixes issue llvm#39558 which mentions the problem when compiling the
following code with `-pedantic-errors` flag (it also mentions `-Wall
-Wextra` but those shouldn't change the output, which is also the case
in GCC):

```c
static void f();

int main()
{
    f;
}
```

Clang only outputs an `undefined-internal` warning on the first line,
but according to 6.9/3

```
"... Moreover, if an identifier declared with internal linkage is used in an
 expression (other than as a part of the operand of a sizeof or _Alignof
 operator whose result is an integer constant), there shall be exactly one
 external definition for the identifier in the translation unit."
```

this should be illegal and hence an error.

I fixed this by changing the warning type from `Warning` to `ExtWarn`
and by adding a suitable test.
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants