mirror of https://github.com/microsoft/clang.git
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:
parent
15b35a3943
commit
37e876e3db
|
@ -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<
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'}} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue