From 9a0efb9546712305b091031889ceccfbc73b6afc Mon Sep 17 00:00:00 2001 From: Momchil Velikov Date: Thu, 10 Aug 2017 15:43:06 +0000 Subject: [PATCH] Place implictly declared functions at block scope Such implicitly declared functions behave as if the enclosing block contained the declaration extern int name() (C90, 6.3.3.2 Function calls), thus their names should have block scope (C90, 6.1.2.1 Scope of identifiers). This patch fixes https://bugs.llvm.org/show_bug.cgi?id=33224 Differential Revision: https://reviews.llvm.org/D33676 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310616 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Scope.h | 8 ++++++ lib/Parse/ParseCXXInlineMethods.cpp | 3 ++- lib/Parse/ParseDecl.cpp | 4 ++- lib/Parse/ParseExpr.cpp | 2 +- lib/Parse/ParseExprCXX.cpp | 3 ++- lib/Parse/ParseObjc.cpp | 22 ++++++++-------- lib/Parse/ParseOpenMP.cpp | 11 +++++--- lib/Parse/ParsePragma.cpp | 3 ++- lib/Parse/ParseStmt.cpp | 17 +++++++------ lib/Parse/ParseTemplate.cpp | 3 ++- lib/Parse/Parser.cpp | 11 +++++--- lib/Sema/SemaDecl.cpp | 8 ++++-- test/Sema/implicit-decl-c90.c | 39 +++++++++++++++++++++++++++++ test/Sema/implicit-decl.c | 5 ++-- 14 files changed, 103 insertions(+), 36 deletions(-) create mode 100644 test/Sema/implicit-decl-c90.c diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index d0b006b82e..e892d8205b 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -124,6 +124,9 @@ public: /// We are currently in the filter expression of an SEH except block. SEHFilterScope = 0x200000, + + /// This is a compound statement scope. + CompoundStmtScope = 0x400000, }; private: /// The parent scope for this scope. This is null for the translation-unit @@ -429,6 +432,11 @@ public: /// \brief Determine whether this scope is a SEH '__except' block. bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; } + /// \brief Determine whether this scope is a compound statement scope. + bool isCompoundStmtScope() const { + return getFlags() & Scope::CompoundStmtScope; + } + /// \brief Returns if rhs has a higher scope depth than this. /// /// The caller is responsible for calling this only if one of the two scopes diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index b68559485a..c9a895d7d5 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -518,7 +518,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Parse the method body. Function body parsing code is similar enough // to be re-used for method bodies as well. - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a4610698c4..f6a315198c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1388,7 +1388,9 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, // If the Decl is on a function, add function parameters to the scope. bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate(); - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunScope); + ParseScope FnScope( + this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope, + HasFunScope); if (HasFunScope) Actions.ActOnReenterFunctionContext(Actions.CurScope, D); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 44b87af01a..f4cdc2201a 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2881,7 +2881,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { // allows determining whether a variable reference inside the block is // within or outside of the block. ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | - Scope::DeclScope); + Scope::CompoundStmtScope | Scope::DeclScope); // Inform sema that we are starting a block. Actions.ActOnBlockStart(CaretLoc, getCurScope()); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index dcafbadae5..56b0327995 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1281,7 +1281,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. - unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; + unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope; ParseScope BodyScope(this, ScopeFlags); Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 01b1bf48e4..edf1da171b 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -2478,7 +2478,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get()); // Parse the compound statement within a new scope. - ParseScope bodyScope(this, Scope::DeclScope); + ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope); StmtResult body(ParseCompoundStatementBody()); bodyScope.Exit(); @@ -2514,7 +2514,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { } StmtVector CatchStmts; StmtResult FinallyStmt; - ParseScope TryScope(this, Scope::DeclScope); + ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope); StmtResult TryBody(ParseCompoundStatementBody()); TryScope.Exit(); if (TryBody.isInvalid()) @@ -2535,7 +2535,9 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { ConsumeToken(); // consume catch if (Tok.is(tok::l_paren)) { ConsumeParen(); - ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope); + ParseScope CatchScope(this, Scope::DeclScope | + Scope::CompoundStmtScope | + Scope::AtCatchScope); if (Tok.isNot(tok::ellipsis)) { DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); @@ -2579,7 +2581,8 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { } else { assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?"); ConsumeToken(); // consume finally - ParseScope FinallyScope(this, Scope::DeclScope); + ParseScope FinallyScope(this, + Scope::DeclScope | Scope::CompoundStmtScope); StmtResult FinallyBody(true); if (Tok.is(tok::l_brace)) @@ -2616,7 +2619,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) { } // Enter a scope to hold everything within the compound stmt. Compound // statements can always hold declarations. - ParseScope BodyScope(this, Scope::DeclScope); + ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope); StmtResult AutoreleasePoolBody(ParseCompoundStatementBody()); @@ -3650,11 +3653,10 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) && "Inline objective-c method not starting with '{' or 'try' or ':'"); // Enter a scope for the method or c-function body. - ParseScope BodyScope(this, - parseMethod - ? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope - : Scope::FnScope|Scope::DeclScope); - + ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) | + Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); + // Tell the actions module that we have entered a method or c-function definition // with the specified Declarator for the method/function. if (parseMethod) diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 353b0795f6..f5638773d9 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -302,6 +302,7 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { for (auto *D : DRD.get()) { TentativeParsingAction TPA(*this); ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope); // Parse expression. Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); @@ -337,6 +338,7 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { IsCorrect; if (Tok.isNot(tok::annot_pragma_openmp_end)) { ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope); // Parse expression. Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D); @@ -405,8 +407,9 @@ public: // If the Decl is on a function, add function parameters to the scope. HasFunScope = D->isFunctionOrFunctionTemplate(); - FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope, - HasFunScope); + FnScope = new Parser::ParseScope( + &P, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope, + HasFunScope); if (HasFunScope) Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D); } @@ -813,8 +816,8 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( SmallVector Clauses; SmallVector, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); - unsigned ScopeFlags = - Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope; + unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ConsumeAnnotationToken(), EndLoc; auto DKind = ParseOpenMPDirectiveKind(*this); OpenMPDirectiveKind CancelRegion = OMPD_unknown; diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index c5215ffcee..198d5c6e9c 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -533,7 +533,8 @@ StmtResult Parser::HandlePragmaCaptured() SourceLocation Loc = Tok.getLocation(); - ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope); + ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, /*NumParams=*/1); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index b1fbb20c72..65c3f21f2d 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -453,9 +453,10 @@ StmtResult Parser::ParseSEHTryBlock() { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); - StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, - Scope::DeclScope | Scope::SEHTryScope)); - if(TryBlock.isInvalid()) + StmtResult TryBlock(ParseCompoundStatement( + /*isStmtExpr=*/false, + Scope::DeclScope | Scope::CompoundStmtScope | Scope::SEHTryScope)); + if (TryBlock.isInvalid()) return TryBlock; StmtResult Handler; @@ -840,7 +841,8 @@ StmtResult Parser::ParseDefaultStatement() { } StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { - return ParseCompoundStatement(isStmtExpr, Scope::DeclScope); + return ParseCompoundStatement(isStmtExpr, + Scope::DeclScope | Scope::CompoundStmtScope); } /// ParseCompoundStatement - Parse a "{}" block. @@ -2085,9 +2087,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); - StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, - Scope::DeclScope | Scope::TryScope | - (FnTry ? Scope::FnTryCatchScope : 0))); + StmtResult TryBlock(ParseCompoundStatement( + /*isStmtExpr=*/false, Scope::DeclScope | Scope::TryScope | + Scope::CompoundStmtScope | + (FnTry ? Scope::FnTryCatchScope : 0))); if (TryBlock.isInvalid()) return TryBlock; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 944cd775d5..fc1722ea6c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -1380,7 +1380,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Parse the method body. Function body parsing code is similar enough // to be re-used for method bodies as well. - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); // Recreate the containing function DeclContext. Sema::ContextRAII FunctionSavedContext(Actions, diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 4aa9a59719..51f4957a6e 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1075,8 +1075,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, TemplateInfo.Kind == ParsedTemplateInfo::Template && Actions.canDelayFunctionBody(D)) { MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); - - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Scope *ParentScope = getCurScope()->getParent(); D.setFunctionDefinitionKind(FDK_Definition); @@ -1106,7 +1107,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) && Actions.CurContext->isTranslationUnit()) { - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Scope *ParentScope = getCurScope()->getParent(); D.setFunctionDefinitionKind(FDK_Definition); @@ -1124,7 +1126,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, } // Enter a scope for the function body. - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6bcb023174..d19ace9c43 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12677,12 +12677,16 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, SourceLocation()); D.SetIdentifier(&II, Loc); - // Insert this function into translation-unit scope. + // 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(ActOnDeclarator(TUScope, D)); + FunctionDecl *FD = cast(ActOnDeclarator(S, D)); FD->setImplicit(); CurContext = PrevDC; diff --git a/test/Sema/implicit-decl-c90.c b/test/Sema/implicit-decl-c90.c new file mode 100644 index 0000000000..38b01759a7 --- /dev/null +++ b/test/Sema/implicit-decl-c90.c @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 %s -std=c90 -verify -fsyntax-only +void t0(int x) { + int (*p)(); + if(x > 0) + x = g() + 1; + p = g; + if(x < 0) { + extern void u(int (*)[h()]); + int (*q)() = h; + } + p = h; /* expected-error {{use of undeclared identifier 'h'}} */ +} + +void t1(int x) { + int (*p)(); + switch (x) { + g(); + case 0: + x = h() + 1; + break; + case 1: + p = g; + p = h; + break; + } + p = g; /* expected-error {{use of undeclared identifier 'g'}} */ + p = h; /* expected-error {{use of undeclared identifier 'h'}} */ +} + +int t2(int x) { + int y = ({ if (x > 0) x = g() + 1; 2*x; }); + int (*p)() = g; /* expected-error {{use of undeclared identifier 'g'}} */ + return y; +} + +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 */ diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c index ffab9a6f91..0a89201078 100644 --- a/test/Sema/implicit-decl.c +++ b/test/Sema/implicit-decl.c @@ -9,8 +9,7 @@ void func() { int32_t *vector[16]; const char compDesc[16 + 1]; int32_t compCount = 0; - if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-note {{previous implicit declaration is here}} \ - 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}} } printg("Hello, World!\n"); // expected-error{{implicit declaration of function 'printg' is invalid in C99}} \ @@ -18,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) { // expected-error{{conflicting types for '_CFCalendarDecomposeAbsoluteTimeV'}} +Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { return 0; } -- 2.50.0