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.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314871 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2017-10-04 01:49:22 +00:00
parent 15b35a3943
commit 37e876e3db
5 changed files with 49 additions and 23 deletions

View File

@ -366,8 +366,10 @@ def err_language_linkage_spec_unknown : Error<"unknown linkage language">;
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<

View File

@ -12613,14 +12613,32 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
/// 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::ImplicitlyDefineFunction(SourceLocation Loc,
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::ImplicitlyDefineFunction(SourceLocation Loc,
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;

View File

@ -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_qualifiers
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

View File

@ -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'}} */

View File

@ -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;
}