r314871 - PR34822: Fix a collection of related bugs with our handling of C89 implicit function declarations.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 3 18:49:22 PDT 2017
Author: rsmith
Date: Tue Oct 3 18:49:22 2017
New Revision: 314871
URL: http://llvm.org/viewvc/llvm-project?rev=314871&view=rev
Log:
PR34822: Fix a collection of related bugs with our handling of C89 implicit function declarations.
We were injecting the function into the wrong semantic context, resulting in it
failing to be registered as a global for redeclaration lookup. As a
consequence, we accepted invalid code since r310616.
Fixing that resulted in the "out-of-scope declaration" diagnostic firing a lot
more often. It turned out that warning codepath was non-conforming, because it
did not cause us to inject the implicitly-declared function into the enclosing
block scope. We now only warn if the type of the out-of-scope declaration
doesn't match the type of an implicitly-declared function; in all other cases,
we produce the normal warning for an implicitly-declared function.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Misc/warning-flags.c
cfe/trunk/test/Sema/implicit-decl-c90.c
cfe/trunk/test/Sema/implicit-decl.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 3 18:49:22 2017
@@ -366,8 +366,10 @@ def err_language_linkage_spec_unknown :
def err_language_linkage_spec_not_ascii : Error<
"string literal in language linkage specifier cannot have an "
"encoding-prefix">;
-def warn_use_out_of_scope_declaration : Warning<
- "use of out-of-scope declaration of %0">;
+def ext_use_out_of_scope_declaration : ExtWarn<
+ "use of out-of-scope declaration of %0%select{| whose type is not "
+ "compatible with that of an implicit declaration}1">,
+ InGroup<DiagGroup<"out-of-scope-function">>;
def err_inline_non_function : Error<
"'inline' can only appear on functions%select{| and non-local variables}0">;
def err_noreturn_non_function : Error<
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Oct 3 18:49:22 2017
@@ -12613,14 +12613,32 @@ void Sema::ActOnFinishDelayedAttribute(S
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
IdentifierInfo &II, Scope *S) {
+ Scope *BlockScope = S;
+ while (!BlockScope->isCompoundStmtScope() && BlockScope->getParent())
+ BlockScope = BlockScope->getParent();
+
// Before we produce a declaration for an implicitly defined
// function, see whether there was a locally-scoped declaration of
// this name as a function or variable. If so, use that
// (non-visible) declaration, and complain about it.
- if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) {
- Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev;
- Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
- return ExternCPrev;
+ NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II);
+ if (ExternCPrev) {
+ // We still need to inject the function into the enclosing block scope so
+ // that later (non-call) uses can see it.
+ PushOnScopeChains(ExternCPrev, BlockScope, /*AddToContext*/false);
+
+ // C89 footnote 38:
+ // If in fact it is not defined as having type "function returning int",
+ // the behavior is undefined.
+ if (!isa<FunctionDecl>(ExternCPrev) ||
+ !Context.typesAreCompatible(
+ cast<FunctionDecl>(ExternCPrev)->getType(),
+ Context.getFunctionNoProtoType(Context.IntTy))) {
+ Diag(Loc, diag::ext_use_out_of_scope_declaration)
+ << ExternCPrev << !getLangOpts().C99;
+ Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
+ return ExternCPrev;
+ }
}
// Extension in C99. Legal in C90, but warn about it.
@@ -12636,6 +12654,12 @@ NamedDecl *Sema::ImplicitlyDefineFunctio
diag_id = diag::warn_implicit_function_decl;
Diag(Loc, diag_id) << &II;
+ // If we found a prior declaration of this function, don't bother building
+ // another one. We've already pushed that one into scope, so there's nothing
+ // more to do.
+ if (ExternCPrev)
+ return ExternCPrev;
+
// Because typo correction is expensive, only do it if the implicit
// function declaration is going to be treated as an error.
if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) {
@@ -12687,19 +12711,9 @@ NamedDecl *Sema::ImplicitlyDefineFunctio
D.SetIdentifier(&II, Loc);
// Insert this function into the enclosing block scope.
- while (S && !S->isCompoundStmtScope())
- S = S->getParent();
- if (S == nullptr)
- S = TUScope;
-
- DeclContext *PrevDC = CurContext;
- CurContext = Context.getTranslationUnitDecl();
-
- FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(S, D));
+ FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(BlockScope, D));
FD->setImplicit();
- CurContext = PrevDC;
-
AddKnownFunctionAttributes(FD);
return FD;
Modified: cfe/trunk/test/Misc/warning-flags.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/warning-flags.c?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/test/Misc/warning-flags.c (original)
+++ cfe/trunk/test/Misc/warning-flags.c Tue Oct 3 18:49:22 2017
@@ -18,7 +18,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (78):
+CHECK: Warnings without flags (77):
CHECK-NEXT: ext_excess_initializers
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
CHECK-NEXT: ext_expected_semi_decl_list
@@ -94,7 +94,6 @@ CHECK-NEXT: warn_typecheck_function_qu
CHECK-NEXT: warn_undef_interface
CHECK-NEXT: warn_undef_interface_suggest
CHECK-NEXT: warn_undef_protocolref
-CHECK-NEXT: warn_use_out_of_scope_declaration
CHECK-NEXT: warn_weak_identifier_undeclared
CHECK-NEXT: warn_weak_import
Modified: cfe/trunk/test/Sema/implicit-decl-c90.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/implicit-decl-c90.c?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/test/Sema/implicit-decl-c90.c (original)
+++ cfe/trunk/test/Sema/implicit-decl-c90.c Tue Oct 3 18:49:22 2017
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 %s -std=c90 -verify -fsyntax-only
void t0(int x) {
+ int explicit_decl();
int (*p)();
if(x > 0)
- x = g() + 1;
+ x = g() + 1; // expected-note {{previous implicit declaration}}
p = g;
if(x < 0) {
extern void u(int (*)[h()]);
@@ -25,6 +26,8 @@ void t1(int x) {
}
p = g; /* expected-error {{use of undeclared identifier 'g'}} */
p = h; /* expected-error {{use of undeclared identifier 'h'}} */
+ explicit_decl();
+ p = explicit_decl;
}
int t2(int x) {
@@ -33,7 +36,15 @@ int t2(int x) {
return y;
}
+int PR34822() {
+ {int i = sizeof(PR34822_foo());} /* expected-note {{previous definition is here}} */
+ {extern int PR34822_foo;} /* expected-error {{redefinition of 'PR34822_foo' as different kind of symbol}} */
+
+ {extern int PR34822_bar;} /* expected-note {{previous declaration is here}} */
+ {int i = sizeof(PR34822_bar());} /* expected-warning {{use of out-of-scope declaration of 'PR34822_bar' whose type is not compatible with that of an implicit declaration}} expected-error {{called object type 'int' is not a function or function pointer}} */
+}
+
int (*p)() = g; /* expected-error {{use of undeclared identifier 'g'}} */
int (*q)() = h; /* expected-error {{use of undeclared identifier 'h'}} */
-float g(); /* not expecting conflicting types diagnostics here */
+float g(); /* expected-error {{conflicting types for 'g'}} */
Modified: cfe/trunk/test/Sema/implicit-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/implicit-decl.c?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/test/Sema/implicit-decl.c (original)
+++ cfe/trunk/test/Sema/implicit-decl.c Tue Oct 3 18:49:22 2017
@@ -9,7 +9,7 @@ void func() {
int32_t *vector[16];
const char compDesc[16 + 1];
int32_t compCount = 0;
- if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}}
+ if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}} expected-note {{previous implicit declaration}}
}
printg("Hello, World!\n"); // expected-error{{implicit declaration of function 'printg' is invalid in C99}} \
@@ -17,7 +17,7 @@ void func() {
__builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}}
}
-Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) {
+Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error {{conflicting types}}
return 0;
}
More information about the cfe-commits
mailing list