aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-09 22:42:13 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-09 22:42:13 +0000
commit3218c4bb3b5d7250f12420de6db7ef3e3f805a75 (patch)
treef6826e25245398cff43f0546bbd58b338864fae2 /lib
parentef64fcfbfb99495d7f9f64c7f0751c2827028733 (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.cpp3
-rw-r--r--lib/Parse/ParseDecl.cpp6
-rw-r--r--lib/Parse/ParseDeclCXX.cpp6
-rw-r--r--lib/Parse/Parser.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp47
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;