diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-01-05 19:45:36 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-01-05 19:45:36 +0000 |
commit | 07665a69e88334ced1648b5e4bcc2dbe2b90e366 (patch) | |
tree | afcb47baaf692b09480bbe21c541f2c86df4cd98 | |
parent | 07ebf302e5086323ddaf824427606d67ffe3b112 (diff) | |
download | bcm5719-llvm-07665a69e88334ced1648b5e4bcc2dbe2b90e366.tar.gz bcm5719-llvm-07665a69e88334ced1648b5e4bcc2dbe2b90e366.zip |
Introduce support for "transparent" DeclContexts, which are
DeclContexts whose members are visible from enclosing DeclContexts up
to (and including) the innermost enclosing non-transparent
DeclContexts. Transparent DeclContexts unify the mechanism to be used
for various language features, including C enumerations, anonymous
unions, C++0x inline namespaces, and C++ linkage
specifications. Please refer to the documentation in the Clang
internals manual for more information.
Only enumerations and linkage specifications currently use transparent
DeclContexts.
Still to do: use transparent DeclContexts to implement anonymous
unions and GCC's anonymous structs extension, and, later, the C++0x
features. We also need to tighten up the DeclContext/ScopedDecl link
to ensure that every ScopedDecl is in a single DeclContext, which
will ensure that we can then enforce ownership and reduce the memory
footprint of DeclContext.
llvm-svn: 61735
-rw-r--r-- | clang/Driver/ASTConsumers.cpp | 8 | ||||
-rw-r--r-- | clang/docs/InternalsManual.html | 301 | ||||
-rw-r--r-- | clang/include/clang/AST/DeclBase.h | 38 | ||||
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 37 | ||||
-rw-r--r-- | clang/include/clang/Parse/Action.h | 46 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 59 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 38 | ||||
-rw-r--r-- | clang/lib/AST/DeclSerialization.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Sema/IdentifierResolver.cpp | 61 | ||||
-rw-r--r-- | clang/lib/Sema/IdentifierResolver.h | 17 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 21 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 53 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 59 | ||||
-rw-r--r-- | clang/test/SemaCXX/qualified-id-lookup.cpp | 8 |
16 files changed, 549 insertions, 245 deletions
diff --git a/clang/Driver/ASTConsumers.cpp b/clang/Driver/ASTConsumers.cpp index 6681ec95f1a..6836d0c6f23 100644 --- a/clang/Driver/ASTConsumers.cpp +++ b/clang/Driver/ASTConsumers.cpp @@ -116,14 +116,14 @@ void DeclPrinter:: PrintDecl(Decl *D) { Out << "};\n"; } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { Out << "Read top-level tag decl: '" << TD->getNameAsString() << "'\n"; - } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) { - Out << "Read top-level variable decl: '" << SD->getNameAsString() << "'\n"; } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) { PrintLinkageSpec(LSD); } else if (FileScopeAsmDecl *AD = dyn_cast<FileScopeAsmDecl>(D)) { Out << "asm("; AD->getAsmString()->printPretty(Out); Out << ")\n"; + } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) { + Out << "Read top-level variable decl: '" << SD->getNameAsString() << "'\n"; } else { assert(0 && "Unknown decl type!"); } @@ -197,8 +197,8 @@ void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) { if (LS->hasBraces()) Out << "{\n"; - for (LinkageSpecDecl::decl_const_iterator D = LS->decls_begin(), - DEnd = LS->decls_end(); + for (LinkageSpecDecl::decl_iterator D = LS->decls_begin(), + DEnd = LS->decls_end(); D != DEnd; ++D) PrintDecl(*D); diff --git a/clang/docs/InternalsManual.html b/clang/docs/InternalsManual.html index 531e5767582..aa96c0df40c 100644 --- a/clang/docs/InternalsManual.html +++ b/clang/docs/InternalsManual.html @@ -44,6 +44,15 @@ td { <li><a href="#Type">The Type class and its subclasses</a></li> <li><a href="#QualType">The QualType class</a></li> <li><a href="#DeclarationName">Declaration names</a></li> + <li><a href="#DeclContext">Declaration contexts</a> + <ul> + <li><a href="#Redeclarations">Redeclarations and Overloads</a></li> + <li><a href="#LexicalAndSemanticContexts">Lexical and Semantic + Contexts</a></li> + <li><a href="#TransparentContexts">Transparent Declaration Contexts</a></li> + <li><a href="#MultiDeclContext">Multiply-Defined Declaration Contexts</a></li> + </ul> + </li> <li><a href="#CFG">The CFG class</a></li> <li><a href="#Constants">Constant Folding in the Clang AST</a></li> </ul> @@ -871,6 +880,298 @@ malloc'd objects are at least 8 byte aligned.</p> C++ special function names.</p> <!-- ======================================================================= --> +<h3 id="DeclContext">Declaration contexts</h3> +<!-- ======================================================================= --> +<p>Every declaration in a program exists within some <i>declaration + context</i>, such as a translation unit, namespace, class, or + function. Declaration contexts in Clang are represented by + the <code>DeclContext</code> class, from which the various + declaration-context AST nodes + (<code>TranslationUnitDecl</code>, <code>NamespaceDecl</code>, <code>RecordDecl</code>, <code>FunctionDecl</code>, + etc.) will derive. The <code>DeclContext</code> class provides + several facilities common to each declaration context:</p> +<dl> + <dt>Source-centric vs. Semantics-centric View of Declarations</dt> + <dd><code>DeclContext</code> provides two views of the declarations + stored within a declaration context. The source-centric view + accurately represents the program source code as written, including + multiple declarations of entities where present (see the + section <a href="#Redeclarations">Redeclarations and + Overloads</a>), while the semantics-centric view represents the + program semantics. The two views are kept synchronized by semantic + analysis while the ASTs are being constructed.</dd> + + <dt>Storage of declarations within that context</dt> + <dd>Every declaration context can contain some number of + declarations. For example, a C++ class (represented + by <code>RecordDecl</code>) contains various member functions, + fields, nested types, and so on. All of these declarations will be + stored within the <code>DeclContext</code>, and one can iterate + over the declarations via + [<code>DeclContext::decls_begin()</code>, + <code>DeclContext::decls_end()</code>). This mechanism provides + the source-centric view of declarations in the context.</dd> + + <dt>Lookup of declarations within that context</dt> + <dd>The <code>DeclContext</code> structure provides efficient name + lookup for names within that declaration context. For example, + if <code>N</code> is a namespace we can look for the + name <code>N::f</code> + using <code>DeclContext::lookup</code>. The lookup itself is + based on a lazily-constructed array (for declaration contexts + with a small number of declarations) or hash table (for + declaration contexts with more declarations). The lookup + operation provides the semantics-centric view of the declarations + in the context.</dd> + + <dt>Ownership of declarations</dt> + <dd>The <code>DeclContext</code> owns all of the declarations that + were declared within its declaration context, and is responsible + for the management of their memory as well as their + (de-)serialization.</dd> +</dl> + +<p>The declarations stored within each declaration context are + called <i>scoped declarations</i> and the AST nodes for each of + these declarations are + derived from the <code>ScopedDecl</code> class, which provides + information about the context in which that declaration lives. One + can retrieve the <code>DeclContext</code> that contains a + particular <code>ScopedDecl</code> + using <code>ScopedDecl::getDeclContext</code>. However, see the + section <a href="#LexicalAndSemanticContexts">Lexical and Semantic + Contexts</a> for more information about how to interpret this + context information.</p> + +<h4 id="Redeclarations">Redeclarations and Overloads</h4> +<p>Within a translation unit, it is common for an entity to be +declared several times. For example, we might declare a function "f" + and then later re-declare it as part of an inlined definition:</p> + +<pre> +void f(int x, int y, int z = 1); + +inline void f(int x, int y, int z) { /* ... */ } +</pre> + +<p>The representation of "f" differs in the source-centric and + semantics-centric views of a declaration context. In the + source-centric view, all redeclarations will be present, in the + order they occurred in the source code, making + this view suitable for clients that wish to see the structure of + the source code. In the semantics-centric view, only the most recent "f" + will be found by the lookup, since it effectively replaces the first + declaration of "f".</p> + +<p>In the semantics-centric view, overloading of functions is + represented explicitly. For example, given two declarations of a + function "g" that are overloaded, e.g.,</p> +<pre> +void g(); +void g(int); +</pre> +<p>the <code>DeclContext::lookup</code> operation will return + an <code>OverloadedFunctionDecl</code> that contains both + declarations of "g". Clients that perform semantic analysis on a + program that is not concerned with the actual source code will + primarily use this semantics-centric view.</p> + +<h4 id="LexicalAndSemanticContexts">Lexical and Semantic Contexts</h4> +<p>Each scoped declaration (whose AST node derived + from <code>ScopedDecl</code>) has two potentially different + declaration contexts: a <i>lexical</i> context, which corresponds to + the source-centric view of the declaration context, and + a <i>semantic</i> context, which corresponds to the + semantics-centric view. The lexical context is accessible + via <code>ScopedDecl::getLexicalDeclContext</code> while the + semantic context is accessible + via <code>ScopedDecl::getDeclContext</code>, both of which return + <code>DeclContext</code> pointers. For most declarations, the two + contexts are identical. For example:</p> + +<pre> +class X { +public: + void f(int x); +}; +</pre> + +<p>Here, the semantic and lexical contexts of <code>X::f</code> are + the <code>DeclContext</code> associated with the + class <code>X</code> (itself stored as a <code>RecordDecl</code> AST + node). However, we can now define <code>X::f</code> out-of-line:</p> + +<pre> +void X::f(int x = 17) { /* ... */ } +</pre> + +<p>This definition of has different lexical and semantic + contexts. The lexical context corresponds to the declaration + context in which the actual declaration occurred in the source + code, e.g., the translation unit containing <code>X</code>. Thus, + this declaration of <code>X::f</code> can be found by traversing + the declarations provided by + [<code>decls_begin()</code>, <code>decls_end()</code>) in the + translation unit.</p> + +<p>The semantic context of <code>X::f</code> corresponds to the + class <code>X</code>, since this member function is (semantically) a + member of <code>X</code>. Lookup of the name <code>f</code> into + the <code>DeclContext</code> associated with <code>X</code> will + then return the definition of <code>X::f</code> (including + information about the default argument).</p> + +<h4 id="TransparentContexts">Transparent Declaration Contexts</h4> +<p>In C and C++, there are several contexts in which names that are + logically declared inside another declaration will actually "leak" + out into the enclosing scope from the perspective of name + lookup. The most obvious instance of this behavior is in + enumeration types, e.g.,</p> +<pre> +enum Color { + Red, + Green, + Blue +}; +</pre> + +<p>Here, <code>Color</code> is an enumeration, which is a declaration + context that contains the + enumerators <code>Red</code>, <code>Green</code>, + and <code>Blue</code>. Thus, traversing the list of declarations + contained in the enumeration <code>Color</code> will + yield <code>Red</code>, <code>Green</code>, + and <code>Blue</code>. However, outside of the scope + of <code>Color</code> one can name the enumerator <code>Red</code> + without qualifying the name, e.g.,</p> + +<pre> +Color c = Red; +</pre> + +<p>There are other entities in C++ that provide similar behavior. For + example, linkage specifications that use curly braces:</p> + +<pre> +extern "C" { + void f(int); + void g(int); +} +// f and g are visible here +</pre> + +<p>For source-level accuracy, we treat the linkage specification and + enumeration type as a + declaration context in which its enclosed declarations ("Red", + "Green", and "Blue"; "f" and "g") + are declared. However, these declarations are visible outside of the + scope of the declaration context.</p> + +<p>These language features (and several others, described below) have + roughly the same set of + requirements: declarations are declared within a particular lexical + context, but the declarations are also found via name lookup in + scopes enclosing the declaration itself. This feature is implemented + via <i>transparent</i> declaration contexts + (see <code>DeclContext::isTransparentContext()</code>), whose + declarations are visible in the nearest enclosing non-transparent + declaration context. This means that the lexical context of the + declaration (e.g., an enumerator) will be the + transparent <code>DeclContext</code> itself, as will the semantic + context, but the declaration will be visible in every outer context + up to and including the first non-transparent declaration context (since + transparent declaration contexts can be nested).</p> + +<p>The transparent <code>DeclContexts</code> are:</p> +<ul> + <li>Enumerations (but not C++0x "scoped enumerations"): + <pre> +enum Color { + Red, + Green, + Blue +}; +// Red, Green, and Blue are in scope + </pre></li> + <li>C++ linkage specifications: + <pre> +extern "C" { + void f(int); + void g(int); +} +// f and g are in scope + </pre></li> + <li>Anonymous unions and structs: + <pre> +struct LookupTable { + bool IsVector; + union { + std::vector<Item> *Vector; + std::set<Item> *Set; + }; +}; + +LookupTable LT; +LT.Vector = 0; // Okay: finds Vector inside the unnamed union + </pre> + </li> + <li>C++0x inline namespaces: +<pre> +namespace mylib { + inline namespace debug { + class X; + } +} +mylib::X *xp; // okay: mylib::X refers to mylib::debug::X +</pre> +</li> +</ul> + + +<h4 id="MultiDeclContext">Multiply-Defined Declaration Contexts</h4> +<p>C++ namespaces have the interesting--and, so far, unique--property that +the namespace can be defined multiple times, and the declarations +provided by each namespace definition are effectively merged (from +the semantic point of view). For example, the following two code +snippets are semantically indistinguishable:</p> +<pre> +// Snippet #1: +namespace N { + void f(); +} +namespace N { + void f(int); +} + +// Snippet #2: +namespace N { + void f(); + void f(int); +} +</pre> + +<p>In Clang's representation, the source-centric view of declaration + contexts will actually have two separate <code>NamespaceDecl</code> + nodes in Snippet #1, each of which is a declaration context that + contains a single declaration of "f". However, the semantics-centric + view provided by name lookup into the namespace <code>N</code> for + "f" will return an <code>OverloadedFunctionDecl</code> that contains + both declarations of "f".</p> + +<p><code>DeclContext</code> manages multiply-defined declaration + contexts internally. The + function <code>DeclContext::getPrimaryContext</code> retrieves the + "primary" context for a given <code>DeclContext</code> instance, + which is the <code>DeclContext</code> responsible for maintaining + the lookup table used for the semantics-centric view. Given the + primary context, one can follow the chain + of <code>DeclContext</code> nodes that define additional + declarations via <code>DeclContext::getNextContext</code>. Note that + these functions are used internally within the lookup and insertion + methods of the <code>DeclContext</code>, so the vast majority of + clients can ignore them.</p> + +<!-- ======================================================================= --> <h3 id="CFG">The <tt>CFG</tt> class</h3> <!-- ======================================================================= --> diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 9ceb7801725..32760f391be 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -31,6 +31,7 @@ class CXXRecordDecl; class EnumDecl; class ObjCMethodDecl; class ObjCInterfaceDecl; +class LinkageSpecDecl; class BlockDecl; class DeclarationName; @@ -80,12 +81,12 @@ public: ParmVar, OriginalParmVar, NonTypeTemplateParm, + LinkageSpec, // [DeclContext] ObjCInterface, // [DeclContext] ObjCCompatibleAlias, ObjCClass, ObjCForwardProtocol, ObjCPropertyImpl, - LinkageSpec, FileScopeAsm, Block, // [DeclContext] @@ -93,7 +94,7 @@ public: // of the class, to allow efficient classof. NamedFirst = OverloadedFunction , NamedLast = NonTypeTemplateParm, FieldFirst = Field , FieldLast = ObjCAtDefsField, - ScopedFirst = Field , ScopedLast = NonTypeTemplateParm, + ScopedFirst = Field , ScopedLast = LinkageSpec, TypeFirst = Typedef , TypeLast = TemplateTypeParm, TagFirst = Enum , TagLast = CXXRecord, RecordFirst = Record , RecordLast = CXXRecord, @@ -260,8 +261,8 @@ protected: /// EnumDecl /// ObjCMethodDecl /// ObjCInterfaceDecl +/// LinkageSpecDecl /// BlockDecl -/// class DeclContext { /// DeclKind - This indicates which class this is. Decl::Kind DeclKind : 8; @@ -299,8 +300,6 @@ class DeclContext { static To *CastTo(const From *D) { Decl::Kind DK = KindTrait<From>::getKind(D); switch(DK) { - case Decl::Block: - return static_cast<BlockDecl*>(const_cast<From*>(D)); case Decl::TranslationUnit: return static_cast<TranslationUnitDecl*>(const_cast<From*>(D)); case Decl::Namespace: @@ -315,6 +314,10 @@ class DeclContext { return static_cast<ObjCMethodDecl*>(const_cast<From*>(D)); case Decl::ObjCInterface: return static_cast<ObjCInterfaceDecl*>(const_cast<From*>(D)); + case Decl::LinkageSpec: + return static_cast<LinkageSpecDecl*>(const_cast<From*>(D)); + case Decl::Block: + return static_cast<BlockDecl*>(const_cast<From*>(D)); default: if (DK >= Decl::FunctionFirst && DK <= Decl::FunctionLast) return static_cast<FunctionDecl*>(const_cast<From*>(D)); @@ -385,6 +388,24 @@ public: return DeclKind == Decl::Namespace; } + /// isTransparentContext - Determines whether this context is a + /// "transparent" context, meaning that the members declared in this + /// context are semantically declared in the nearest enclosing + /// non-transparent (opaque) context but are lexically declared in + /// this context. For example, consider the enumerators of an + /// enumeration type: + /// @code + /// enum E { + /// Val1 + /// }; + /// @endcode + /// Here, E is a transparent context, so its enumerator (Val1) will + /// appear (semantically) that it is in the same context of E. + /// Examples of transparent contexts include: enumerations (except for + /// C++0x scoped enums), C++ linkage specifications, and C++0x + /// inline namespaces. + bool isTransparentContext() const; + bool Encloses(DeclContext *DC) const { for (; DC; DC = DC->getParent()) if (DC == this) @@ -435,10 +456,7 @@ public: /// declaration into data structure for name lookup. void addDecl(ASTContext &Context, ScopedDecl *D, bool AllowLookup = true); - /// reverseDeclChain - Reverse the chain of declarations stored in - /// this scope. Typically called once after all declarations have - /// been added and the scope is closed. - void reverseDeclChain(); + void buildLookup(ASTContext &Context, DeclContext *DCtx); /// lookup_iterator - An iterator that provides access to the results /// of looking up a name within this context. @@ -484,6 +502,7 @@ public: case Decl::CXXRecord: case Decl::ObjCMethod: case Decl::ObjCInterface: + case Decl::LinkageSpec: case Decl::Block: return true; default: @@ -502,6 +521,7 @@ public: static bool classof(const EnumDecl *D) { return true; } static bool classof(const ObjCMethodDecl *D) { return true; } static bool classof(const ObjCInterfaceDecl *D) { return true; } + static bool classof(const LinkageSpecDecl *D) { return true; } static bool classof(const BlockDecl *D) { return true; } private: diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index d66e1a241ea..6f156fa8270 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -882,7 +882,7 @@ public: /// LinkageSpecDecl - This represents a linkage specification. For example: /// extern "C" void foo(); /// -class LinkageSpecDecl : public Decl { +class LinkageSpecDecl : public ScopedDecl, public DeclContext { public: /// LanguageIDs - Used to represent the language in a linkage /// specification. The values are part of the serialization abi for @@ -898,43 +898,22 @@ private: /// HadBraces - Whether this linkage specification had curly braces or not. bool HadBraces : 1; - /// Decls - The declarations that were parsed as part of this - /// linkage specification. If HadBraces is false, this is a - /// Decl*. Otherwise, it's a Decl**. - void *Decls; - - /// NumDecls - The number of declarations stored in this linkage - /// specification. - unsigned NumDecls : 31; - - LinkageSpecDecl(SourceLocation L, LanguageIDs lang, Decl *d) - : Decl(LinkageSpec, L), Language(lang), HadBraces(false), - Decls(d), NumDecls(1) {} - - LinkageSpecDecl(SourceLocation L, LanguageIDs lang, - Decl **InDecls, unsigned InNumDecls); + LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang, + bool Braces) + : ScopedDecl(LinkageSpec, DC, L, DeclarationName(), 0), + DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { } public: - ~LinkageSpecDecl(); + static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, LanguageIDs Lang, + bool Braces); - static LinkageSpecDecl *Create(ASTContext &C, SourceLocation L, - LanguageIDs Lang, Decl *D); - - static LinkageSpecDecl *Create(ASTContext &C, SourceLocation L, - LanguageIDs Lang, - Decl **Decls, unsigned NumDecls); - LanguageIDs getLanguage() const { return Language; } /// hasBraces - Determines whether this linkage specification had /// braces in its syntactic form. bool hasBraces() const { return HadBraces; } - typedef Decl** decl_iterator; - typedef Decl** decl_const_iterator; - decl_const_iterator decls_begin() const; - decl_const_iterator decls_end() const; - static bool classof(const Decl *D) { return D->getKind() == LinkageSpec; } diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index fb1d9d4c0eb..096104b9159 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -264,25 +264,32 @@ public: return 0; } - /// ActOnLinkageSpec - Parsed a C++ linkage-specification that - /// contained braces. Lang/StrSize contains the language string that - /// was parsed at location Loc. Decls/NumDecls provides the - /// declarations parsed inside the linkage specification. - virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace, - SourceLocation RBrace, const char *Lang, - unsigned StrSize, - DeclTy **Decls, unsigned NumDecls) { - return 0; + /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ + /// linkage specification, including the language and (if present) + /// the '{'. ExternLoc is the location of the 'extern', LangLoc is + /// the location of the language string literal, which is provided + /// by Lang/StrSize. LBraceLoc, if valid, provides the location of + /// the '{' brace. Otherwise, this linkage specification does not + /// have any braces. + virtual DeclTy *ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + const char *Lang, + unsigned StrSize, + SourceLocation LBraceLoc) { + return 0; + } + + /// ActOnFinishLinkageSpecification - Completely the definition of + /// the C++ linkage specification LinkageSpec. If RBraceLoc is + /// valid, it's the position of the closing '}' brace in a linkage + /// specification that uses braces. + virtual DeclTy *ActOnFinishLinkageSpecification(Scope *S, + DeclTy *LinkageSpec, + SourceLocation RBraceLoc) { + return LinkageSpec; } - /// ActOnLinkageSpec - Parsed a C++ linkage-specification without - /// braces. Lang/StrSize contains the language string that was - /// parsed at location Loc. D is the declaration parsed. - virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *Lang, - unsigned StrSize, DeclTy *D) { - return 0; - } - /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. @@ -333,6 +340,11 @@ public: SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList) {} + /// ActOnEnumStartDefinition - Invoked when we have entered the + /// scope of the enumeration body and will be parsing its + /// enumerators. + virtual void ActOnEnumStartDefinition(Scope *S, DeclTy *EnumDecl) { } + virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl, DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index c6b3c53cc42..59d8a07bfdd 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -406,10 +406,24 @@ void DeclContext::DestroyDecls(ASTContext &C) { } } +bool DeclContext::isTransparentContext() const { + if (DeclKind == Decl::Enum) + return true; // FIXME: Check for C++0x scoped enums + else if (DeclKind == Decl::LinkageSpec) + return true; + else if (DeclKind == Decl::Record || DeclKind == Decl::CXXRecord) + return false; // FIXME: need to know about anonymous unions/structs + else if (DeclKind == Decl::Namespace) + return false; // FIXME: Check for C++0x inline namespaces + + return false; +} + DeclContext *DeclContext::getPrimaryContext(ASTContext &Context) { switch (DeclKind) { - case Decl::Block: case Decl::TranslationUnit: + case Decl::LinkageSpec: + case Decl::Block: // There is only one DeclContext for these entities. return this; @@ -418,10 +432,15 @@ DeclContext *DeclContext::getPrimaryContext(ASTContext &Context) { return static_cast<NamespaceDecl*>(this)->getOriginalNamespace(); case Decl::Enum: +#if 0 + // FIXME: See the comment for CXXRecord, below. // The declaration associated with the enumeration type is our // primary context. return Context.getTypeDeclType(static_cast<EnumDecl*>(this)) ->getAsEnumType()->getDecl(); +#else + return this; +#endif case Decl::Record: case Decl::CXXRecord: { @@ -461,13 +480,14 @@ DeclContext *DeclContext::getPrimaryContext(ASTContext &Context) { DeclContext *DeclContext::getNextContext() { switch (DeclKind) { - case Decl::Block: case Decl::TranslationUnit: case Decl::Enum: case Decl::Record: case Decl::CXXRecord: case Decl::ObjCMethod: case Decl::ObjCInterface: + case Decl::LinkageSpec: + case Decl::Block: // There is only one DeclContext for these entities. return 0; @@ -488,6 +508,24 @@ void DeclContext::addDecl(ASTContext &Context, ScopedDecl *D, bool AllowLookup) D->getDeclContext()->insert(Context, D); } +/// buildLookup - Build the lookup data structure with all of the +/// declarations in DCtx (and any other contexts linked to it or +/// transparent contexts nested within it). +void DeclContext::buildLookup(ASTContext &Context, DeclContext *DCtx) { + for (; DCtx; DCtx = DCtx->getNextContext()) { + for (decl_iterator D = DCtx->decls_begin(); D != DCtx->decls_end(); ++D) { + // Insert this declaration into the lookup structure + insertImpl(*D); + + // If this declaration is itself a transparent declaration context, + // add its members (recursively). + if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) + if (InnerCtx->isTransparentContext()) + buildLookup(Context, InnerCtx->getPrimaryContext(Context)); + } + } +} + DeclContext::lookup_result DeclContext::lookup(ASTContext &Context, DeclarationName Name) { DeclContext *PrimaryContext = getPrimaryContext(Context); @@ -497,11 +535,8 @@ DeclContext::lookup(ASTContext &Context, DeclarationName Name) { /// If there is no lookup data structure, build one now by walking /// all of the linked DeclContexts (in declaration order!) and /// inserting their values. - if (LookupPtr.getPointer() == 0) { - for (DeclContext *DCtx = this; DCtx; DCtx = DCtx->getNextContext()) - for (decl_iterator D = DCtx->decls_begin(); D != DCtx->decls_end(); ++D) - insertImpl(*D); - } + if (LookupPtr.getPointer() == 0) + buildLookup(Context, this); if (isLookupMap()) { StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr.getPointer()); @@ -543,9 +578,19 @@ void DeclContext::insert(ASTContext &Context, ScopedDecl *D) { // someone asks for it. if (LookupPtr.getPointer()) insertImpl(D); + + + // If we are a transparent context, insert into our parent context, + // too. This operation is recursive. + if (isTransparentContext()) + getParent()->insert(Context, D); } void DeclContext::insertImpl(ScopedDecl *D) { + // Skip unnamed declarations. + if (!D->getDeclName()) + return; + bool MayBeRedeclaration = true; if (!isLookupMap()) { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 27065a75bae..66afac8524c 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -291,42 +291,10 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, return new (Mem) OverloadedFunctionDecl(DC, N); } -LinkageSpecDecl::LinkageSpecDecl(SourceLocation L, LanguageIDs lang, - Decl **InDecls, unsigned InNumDecls) - : Decl(LinkageSpec, L), Language(lang), HadBraces(true), - Decls(0), NumDecls(InNumDecls) { - Decl **NewDecls = new Decl*[NumDecls]; - for (unsigned I = 0; I < NumDecls; ++I) - NewDecls[I] = InDecls[I]; - Decls = NewDecls; -} - -LinkageSpecDecl::~LinkageSpecDecl() { - if (HadBraces) - delete [] (Decl**)Decls; -} - LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, + DeclContext *DC, SourceLocation L, - LanguageIDs Lang, Decl *D) { + LanguageIDs Lang, bool Braces) { void *Mem = C.getAllocator().Allocate<LinkageSpecDecl>(); - return new (Mem) LinkageSpecDecl(L, Lang, D); -} - -LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, - SourceLocation L, - LanguageIDs Lang, - Decl **Decls, unsigned NumDecls) { - void *Mem = C.getAllocator().Allocate<LinkageSpecDecl>(); - return new (Mem) LinkageSpecDecl(L, Lang, Decls, NumDecls); -} - -LinkageSpecDecl::decl_const_iterator LinkageSpecDecl::decls_begin() const { - if (hasBraces()) return (Decl**)Decls; - else return (Decl**)&Decls; -} - -LinkageSpecDecl::decl_iterator LinkageSpecDecl::decls_end() const { - if (hasBraces()) return (Decl**)Decls + NumDecls; - else return (Decl**)&Decls + 1; + return new (Mem) LinkageSpecDecl(DC, L, Lang, Braces); } diff --git a/clang/lib/AST/DeclSerialization.cpp b/clang/lib/AST/DeclSerialization.cpp index 68412f968a5..0a298139bd9 100644 --- a/clang/lib/AST/DeclSerialization.cpp +++ b/clang/lib/AST/DeclSerialization.cpp @@ -686,29 +686,12 @@ void LinkageSpecDecl::EmitInRec(Serializer& S) const { Decl::EmitInRec(S); S.EmitInt(getLanguage()); S.EmitBool(HadBraces); - if (HadBraces) { - S.EmitInt(NumDecls); - for (decl_const_iterator D = decls_begin(), DEnd = decls_end(); - D != DEnd; ++D) - S.EmitPtr(*D); - } else { - S.EmitPtr((Decl*)Decls); - } } void LinkageSpecDecl::ReadInRec(Deserializer& D, ASTContext& C) { Decl::ReadInRec(D, C); Language = static_cast<LanguageIDs>(D.ReadInt()); HadBraces = D.ReadBool(); - if (HadBraces) { - NumDecls = D.ReadInt(); - Decl **NewDecls = new Decl*[NumDecls]; - Decls = NewDecls; - for (unsigned I = 0; I < NumDecls; ++I) - D.ReadPtr(NewDecls[I]); - } else { - D.ReadPtr(this->Decls); - } } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c063654781a..a2fdf418627 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1123,6 +1123,10 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { /// identifier /// void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { + // Enter the scope of the enum body and start the definition. + ParseScope EnumScope(this, Scope::DeclScope); + Actions.ActOnEnumStartDefinition(CurScope, EnumDecl); + SourceLocation LBraceLoc = ConsumeBrace(); // C does not allow an empty enumerator-list, C++ does [dcl.enum]. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 32367630214..0b06006d9d0 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -108,27 +108,28 @@ Parser::DeclTy *Parser::ParseLinkage(unsigned Context) { unsigned StrSize = PP.getSpelling(Tok, LangBufPtr); SourceLocation Loc = ConsumeStringToken(); - DeclTy *D = 0; - - if (Tok.isNot(tok::l_brace)) { - D = ParseDeclarationOrFunctionDefinition(); - if (D) - return Actions.ActOnLinkageSpec(Loc, LangBufPtr, StrSize, D); - return 0; + ParseScope LinkageScope(this, Scope::DeclScope); + DeclTy *LinkageSpec + = Actions.ActOnStartLinkageSpecification(CurScope, + /*FIXME: */SourceLocation(), + Loc, LangBufPtr, StrSize, + Tok.is(tok::l_brace)? Tok.getLocation() + : SourceLocation()); + + if (Tok.isNot(tok::l_brace)) { + ParseDeclarationOrFunctionDefinition(); + return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, + SourceLocation()); } SourceLocation LBrace = ConsumeBrace(); - llvm::SmallVector<DeclTy *, 8> InnerDecls; while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - D = ParseExternalDeclaration(); - if (D) - InnerDecls.push_back(D); + ParseExternalDeclaration(); } SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); - return Actions.ActOnLinkageSpec(Loc, LBrace, RBrace, LangBufPtr, StrSize, - &InnerDecls.front(), InnerDecls.size()); + return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, RBrace); } /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index 027beede491..18e78a0d170 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -60,6 +60,9 @@ DeclContext *IdentifierResolver::LookupContext::getContext(Decl *D) { else return TUCtx(); + while (Ctx->isTransparentContext()) + Ctx = Ctx->getParent(); + if (isa<TranslationUnitDecl>(Ctx)) return TUCtx(); @@ -83,30 +86,12 @@ bool IdentifierResolver::LookupContext::isEqOrContainedBy( // IdDeclInfo Implementation //===----------------------------------------------------------------------===// -/// FindContext - Returns an iterator pointing just after the decl that is -/// in the given context or in a parent of it. The search is in reverse -/// order, from end to begin. -IdentifierResolver::IdDeclInfo::DeclsTy::iterator -IdentifierResolver::IdDeclInfo::FindDeclVisibleInContext( - const LookupContext &Ctx, - const DeclsTy::iterator &Start) { - for (DeclsTy::iterator I = Start; I != Decls.begin(); --I) { - if (Ctx.isEqOrContainedBy(LookupContext(*(I-1)))) - return I; - } - - return Decls.begin(); -} - /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must /// be already added to the scope chain and must be in the same context as /// the decl that we want to add. void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D, NamedDecl *Shadow) { - assert(LookupContext(D) == LookupContext(Shadow) && - "Decl and Shadow not in same context!"); - for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { if (Shadow == *(I-1)) { Decls.insert(I-1, D); @@ -147,7 +132,15 @@ IdentifierResolver::~IdentifierResolver() { /// true if 'D' belongs to the given declaration context. bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, Scope *S) const { + while (Ctx->isTransparentContext()) + Ctx = Ctx->getParent(); + if (Ctx->isFunctionOrMethod()) { + // Ignore the scopes associated within transparent declaration contexts. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext()) + S = S->getParent(); + if (S->isDeclScope(D)) return true; if (LangOpt.CPlusPlus) { @@ -201,7 +194,6 @@ void IdentifierResolver::AddDecl(NamedDecl *D) { /// encountered before the 'D' decl. void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) { assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!"); - assert(LookupContext(D) == LookupContext(Shadow) && "Different context!"); DeclarationName Name = D->getDeclName(); void *Ptr = Name.getFETokenInfo<void>(); @@ -252,30 +244,14 @@ IdentifierResolver::begin(DeclarationName Name, const DeclContext *Ctx, void *Ptr = Name.getFETokenInfo<void>(); if (!Ptr) return end(); - LookupContext LC(Ctx); - if (isDeclPtr(Ptr)) { NamedDecl *D = static_cast<NamedDecl*>(Ptr); - LookupContext DC(D); - - if (( LookInParentCtx && LC.isEqOrContainedBy(DC)) || - (!LookInParentCtx && LC == DC)) - return iterator(D); - else - return end(); + return iterator(D); } IdDeclInfo *IDI = toIdDeclInfo(Ptr); - IdDeclInfo::DeclsTy::iterator I; - if (LookInParentCtx) - I = IDI->FindDeclVisibleInContext(LC); - else { - for (I = IDI->decls_end(); I != IDI->decls_begin(); --I) - if (LookupContext(*(I-1)) == LC) - break; - } - + IdDeclInfo::DeclsTy::iterator I = IDI->decls_end(); if (I != IDI->decls_begin()) return iterator(I-1, LookInParentCtx); else // No decls found. @@ -285,22 +261,11 @@ IdentifierResolver::begin(DeclarationName Name, const DeclContext *Ctx, /// PreIncIter - Do a preincrement when 'Ptr' is a BaseIter. void IdentifierResolver::iterator::PreIncIter() { NamedDecl *D = **this; - LookupContext Ctx(D); void *InfoPtr = D->getDeclName().getFETokenInfo<void>(); assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?"); IdDeclInfo *Info = toIdDeclInfo(InfoPtr); BaseIter I = getIterator(); - if (LookInParentCtx()) - I = Info->FindDeclVisibleInContext(Ctx, I); - else { - if (I != Info->decls_begin() && LookupContext(*(I-1)) != Ctx) { - // The next decl is in different declaration context. - // Skip remaining decls and set the iterator to the end. - I = Info->decls_begin(); - } - } - if (I != Info->decls_begin()) *this = iterator(I-1, LookInParentCtx()); else // No more decls. diff --git a/clang/lib/Sema/IdentifierResolver.h b/clang/lib/Sema/IdentifierResolver.h index 30846dcd174..3dab1b53a75 100644 --- a/clang/lib/Sema/IdentifierResolver.h +++ b/clang/lib/Sema/IdentifierResolver.h @@ -91,22 +91,7 @@ class IdentifierResolver { inline DeclsTy::iterator decls_begin() { return Decls.begin(); } inline DeclsTy::iterator decls_end() { return Decls.end(); } - /// FindContext - Returns an iterator pointing just after the decl that is - /// in the given context or in a parent of it. The search is in reverse - /// order, from end to begin. - DeclsTy::iterator FindDeclVisibleInContext(const LookupContext &Ctx) { - return FindDeclVisibleInContext(Ctx, Decls.end()); - } - - /// FindContext - Returns an iterator pointing just after the decl that is - /// in the given context or in a parent of it. The search is in reverse - /// order, from end to begin. - DeclsTy::iterator FindDeclVisibleInContext(const LookupContext &Ctx, - const DeclsTy::iterator &Start); - - void AddDecl(NamedDecl *D) { - Decls.insert(FindDeclVisibleInContext(LookupContext(D)), D); - } + void AddDecl(NamedDecl *D) { Decls.push_back(D); } /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index ca151760c59..d3f373f4949 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -288,12 +288,6 @@ public: virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D); virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtArg Body); - virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace, - SourceLocation RBrace, const char *Lang, - unsigned StrSize, - DeclTy **Decls, unsigned NumDecls); - virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *Lang, - unsigned StrSize, DeclTy *D); virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr); /// Scope actions. @@ -326,6 +320,7 @@ public: DeclTy **Fields, unsigned NumFields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); + virtual void ActOnEnumStartDefinition(Scope *S, DeclTy *EnumDecl); virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl, DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, @@ -980,6 +975,20 @@ public: SourceLocation RParenLoc); //===--------------------------------------------------------------------===// + // C++ Declarations + // + virtual DeclTy *ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + const char *Lang, + unsigned StrSize, + SourceLocation LBraceLoc); + virtual DeclTy *ActOnFinishLinkageSpecification(Scope *S, + DeclTy *LinkageSpec, + SourceLocation RBraceLoc); + + + //===--------------------------------------------------------------------===// // C++ Classes // virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 21d3ad68a0e..f4677f03f41 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -93,6 +93,13 @@ void Sema::PopDeclContext() { /// Add this decl to the scope shadowed decl chains. void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { + // Move up the scope chain until we find the nearest enclosing + // non-transparent context. The declaration will be introduced into this + // scope. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext()) + S = S->getParent(); + S->AddDecl(D); // Add scoped declarations into their context, so that they can be @@ -149,8 +156,11 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { // We are pushing the name of a function, which might be an // overloaded name. FunctionDecl *FD = cast<FunctionDecl>(D); + DeclContext *DC = FD->getDeclContext(); + while (DC->isTransparentContext()) + DC = DC->getParent(); IdentifierResolver::iterator Redecl - = std::find_if(IdResolver.begin(FD->getDeclName(), CurContext, + = std::find_if(IdResolver.begin(FD->getDeclName(), DC, false/*LookInParentCtx*/), IdResolver.end(), std::bind1st(std::mem_fun(&ScopedDecl::declarationReplaces), @@ -337,7 +347,7 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, Ctx = Ctx->getParent(); } - if (!LookInParent) + if (!LookInParent && !Ctx->isTransparentContext()) return 0; } } @@ -3117,6 +3127,15 @@ void Sema::ActOnFields(Scope* S, ProcessDeclAttributeList(Record, Attr); } +void Sema::ActOnEnumStartDefinition(Scope *S, DeclTy *EnumD) { + EnumDecl *Enum = cast_or_null<EnumDecl>((Decl *)EnumD); + + if (Enum) { + // Enter the enumeration context. + PushDeclContext(S, Enum); + } +} + Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, DeclTy *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, @@ -3212,20 +3231,22 @@ Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, DeclTy **Elements, unsigned NumElements) { EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX)); + QualType EnumType = Context.getTypeDeclType(Enum); - if (Enum) { - if (EnumDecl *Def = cast_or_null<EnumDecl>(Enum->getDefinition(Context))) { - // Diagnose code like: - // enum e0 { - // E0 = sizeof(enum e0 { E1 }) - // }; - Diag(Def->getLocation(), diag::err_nested_redefinition) - << Enum->getDeclName(); - Diag(Enum->getLocation(), diag::note_previous_definition); - Enum->setInvalidDecl(); - return; - } + if (EnumType->getAsEnumType()->getDecl()->isDefinition()) { + EnumDecl *Def = EnumType->getAsEnumType()->getDecl(); + // Diagnose code like: + // enum e0 { + // E0 = sizeof(enum e0 { E1 }) + // }; + Diag(Def->getLocation(), diag::err_nested_redefinition) + << Enum->getDeclName(); + Diag(Enum->getLocation(), diag::note_previous_definition); + Enum->setInvalidDecl(); + PopDeclContext(); + return; } + // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. @@ -3239,7 +3260,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, // Keep track of whether all elements have type int. bool AllElementsInt = true; - QualType EnumType = Context.getTypeDeclType(Enum); EnumConstantDecl *EltList = 0; for (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = @@ -3392,6 +3412,9 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, Enum->completeDefinition(Context, BestType); Consumer.HandleTagDeclDefinition(Enum); + + // Leave the context of the enumeration. + PopDeclContext(); } Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e3c8373723e..7c05f6b4970 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2003,48 +2003,49 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { return false; } -/// ActOnLinkageSpec - Parsed a C++ linkage-specification that -/// contained braces. Lang/StrSize contains the language string that -/// was parsed at location Loc. Decls/NumDecls provides the -/// declarations parsed inside the linkage specification. -Sema::DeclTy *Sema::ActOnLinkageSpec(SourceLocation Loc, - SourceLocation LBrace, - SourceLocation RBrace, - const char *Lang, - unsigned StrSize, - DeclTy **Decls, unsigned NumDecls) { +/// ActOnStartLinkageSpecification - Parsed the beginning of a C++ +/// linkage specification, including the language and (if present) +/// the '{'. ExternLoc is the location of the 'extern', LangLoc is +/// the location of the language string literal, which is provided +/// by Lang/StrSize. LBraceLoc, if valid, provides the location of +/// the '{' brace. Otherwise, this linkage specification does not +/// have any braces. +Sema::DeclTy *Sema::ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + const char *Lang, + unsigned StrSize, + SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; if (strncmp(Lang, "\"C\"", StrSize) == 0) Language = LinkageSpecDecl::lang_c; else if (strncmp(Lang, "\"C++\"", StrSize) == 0) Language = LinkageSpecDecl::lang_cxx; else { - Diag(Loc, diag::err_bad_language); + Diag(LangLoc, diag::err_bad_language); return 0; } // FIXME: Add all the various semantics of linkage specifications - return LinkageSpecDecl::Create(Context, Loc, Language, - (Decl **)Decls, NumDecls); + LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, + LangLoc, Language, + LBraceLoc.isValid()); + CurContext->addDecl(Context, D); + PushDeclContext(S, D); + return D; } -Sema::DeclTy *Sema::ActOnLinkageSpec(SourceLocation Loc, - const char *Lang, unsigned StrSize, - DeclTy *D) { - LinkageSpecDecl::LanguageIDs Language; - Decl *dcl = static_cast<Decl *>(D); - if (strncmp(Lang, "\"C\"", StrSize) == 0) - Language = LinkageSpecDecl::lang_c; - else if (strncmp(Lang, "\"C++\"", StrSize) == 0) - Language = LinkageSpecDecl::lang_cxx; - else { - Diag(Loc, diag::err_bad_language); - return 0; - } - - // FIXME: Add all the various semantics of linkage specifications - return LinkageSpecDecl::Create(Context, Loc, Language, dcl); +/// ActOnFinishLinkageSpecification - Completely the definition of +/// the C++ linkage specification LinkageSpec. If RBraceLoc is +/// valid, it's the position of the closing '}' brace in a linkage +/// specification that uses braces. +Sema::DeclTy *Sema::ActOnFinishLinkageSpecification(Scope *S, + DeclTy *LinkageSpec, + SourceLocation RBraceLoc) { + if (LinkageSpec) + PopDeclContext(); + return LinkageSpec; } /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch diff --git a/clang/test/SemaCXX/qualified-id-lookup.cpp b/clang/test/SemaCXX/qualified-id-lookup.cpp index 064f5c90934..1321d734d98 100644 --- a/clang/test/SemaCXX/qualified-id-lookup.cpp +++ b/clang/test/SemaCXX/qualified-id-lookup.cpp @@ -2,15 +2,23 @@ namespace Ns { int f(); // expected-note{{previous declaration is here}} + + enum E { + Enumerator + }; } namespace Ns { double f(); // expected-error{{functions that differ only in their return type cannot be overloaded}} + + int x = Enumerator; } namespace Ns2 { float f(); } +int y = Ns::Enumerator; + namespace Ns2 { float f(int); // expected-note{{previous declaration is here}} } |