diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-01-09 22:42:13 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-01-09 22:42:13 +0000 |
commit | 3218c4bb3b5d7250f12420de6db7ef3e3f805a75 (patch) | |
tree | f6826e25245398cff43f0546bbd58b338864fae2 /lib | |
parent | ef64fcfbfb99495d7f9f64c7f0751c2827028733 (diff) |
When we see a reference to a struct, class, or union like "struct X"
that is neither a definition nor a forward declaration and where X has
not yet been declared as a tag, introduce a declaration
into the appropriate scope (which is likely *not* to be the current
scope). The rules for the placement of the declaration differ slightly
in C and C++, so we implement both and test the various corner
cases. This implementation isn't 100% correct due to some lingering
issues with the function prototype scope (for a function parameter
list) not being the same scope as the scope of the function
definition. Testcase is FIXME'd; this probably isn't an important issue.
Addresses <rdar://problem/6484805>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62014 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 47 |
5 files changed, 53 insertions, 11 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index a9712fe9ed..90d2f6fefc 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -75,7 +75,8 @@ void Parser::ParseLexedMethodDeclarations() { // Introduce the parameters into scope and parse their default // arguments. - ParseScope PrototypeScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { // Introduce the parameter into scope. Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 219295fa74..ac1a4be845 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -526,7 +526,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // constructor declaration. We're done with the decl-specifiers // and will treat this token as an identifier. if (getLang().CPlusPlus && - CurScope->isCXXClassScope() && + CurScope->isClassScope() && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && NextToken().getKind() == tok::l_paren) goto DoneWithDeclSpec; @@ -948,7 +948,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, unsigned TagType, DeclTy *TagDecl) { SourceLocation LBraceLoc = ConsumeBrace(); - ParseScope StructScope(this, Scope::DeclScope); + ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(CurScope, TagDecl); // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in @@ -1875,7 +1875,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. - ParseScope PrototypeScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); bool IsVariadic = false; while (1) { diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c6c2ae4cfe..26787aec12 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -720,7 +720,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation LBraceLoc = ConsumeBrace(); - if (!CurScope->isCXXClassScope() && // Not about to define a nested class. + if (!CurScope->isClassScope() && // Not about to define a nested class. CurScope->isInCXXInlineMethodScope()) { // We will define a local class of an inline method. // Push a new LexedMethodsForTopClass for its inline methods. @@ -728,7 +728,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } // Enter a scope for the class. - ParseScope ClassScope(this, Scope::CXXClassScope|Scope::DeclScope); + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(CurScope, TagDecl); @@ -782,7 +782,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // // FIXME: Only function bodies and constructor ctor-initializers are // parsed correctly, fix the rest. - if (!CurScope->getParent()->isCXXClassScope()) { + if (!CurScope->getParent()->isClassScope()) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d9b39099e0..799a2072f1 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -570,7 +570,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. - ParseScope PrototypeScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); // Read all the argument declarations. while (isDeclarationSpecifier()) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ee72a98295..39b9c787cf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2859,6 +2859,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, } DeclContext *DC = CurContext; + DeclContext *LexicalContext = CurContext; ScopedDecl *PrevDecl = 0; if (Name && SS.isNotEmpty()) { @@ -2971,6 +2972,35 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, PrevDecl = 0; } } + } else if (TK == TK_Reference && SS.isEmpty() && Name && + (Kind != TagDecl::TK_enum)) { + // C++ [basic.scope.pdecl]p5: + // -- for an elaborated-type-specifier of the form + // + // class-key identifier + // + // if the elaborated-type-specifier is used in the + // decl-specifier-seq or parameter-declaration-clause of a + // function defined in namespace scope, the identifier is + // declared as a class-name in the namespace that contains + // the declaration; otherwise, except as a friend + // declaration, the identifier is declared in the smallest + // non-class, non-function-prototype scope that contains the + // declaration. + // + // C99 6.7.2.3p8 has a similar (but not identical!) provision for + // C structs and unions. + + // Find the context where we'll be declaring the tag. + while (DC->isRecord()) + DC = DC->getParent(); + LexicalContext = DC; + + // Find the scope where we'll be declaring the tag. + while (S->isClassScope() || + (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) || + (S->getFlags() & Scope::DeclScope == 0)) + S = S->getParent(); } CreateNewDecl: @@ -3025,9 +3055,13 @@ CreateNewDecl: if (Attr) ProcessDeclAttributeList(New, Attr); + // If we're declaring or defining + if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus) + Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); + // Set the lexical context. If the tag has a C++ scope specifier, the // lexical context will be different from the semantic context. - New->setLexicalDeclContext(CurContext); + New->setLexicalDeclContext(LexicalContext); // If this has an identifier, add it to the scope stack. if (Name) { @@ -3037,13 +3071,20 @@ CreateNewDecl: S = S->getParent(); // Add it to the decl chain. - PushOnScopeChains(New, S); + if (LexicalContext != CurContext) { + // FIXME: PushOnScopeChains should not rely on CurContext! + DeclContext *OldContext = CurContext; + CurContext = LexicalContext; + PushOnScopeChains(New, S); + CurContext = OldContext; + } else + PushOnScopeChains(New, S); } else if (getLangOptions().CPlusPlus) { // FIXME: We also want to do this for C, but if this tag is // defined within a structure CurContext will point to the context // enclosing the structure, and we would end up inserting the tag // type into the wrong place. - CurContext->addDecl(Context, New); + LexicalContext->addDecl(Context, New); } return New; |