aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-05 19:45:36 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-05 19:45:36 +0000
commit074149e11baf5f7db12f84efd5c34ba6e35d5cdf (patch)
treea02b3f87f914315d7ac21bc25fddf46250229d59
parente1dccaefe2d44a9f83f8c3f087438a3297254cac (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61735 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--Driver/ASTConsumers.cpp8
-rw-r--r--docs/InternalsManual.html301
-rw-r--r--include/clang/AST/DeclBase.h38
-rw-r--r--include/clang/AST/DeclCXX.h37
-rw-r--r--include/clang/Parse/Action.h46
-rw-r--r--lib/AST/DeclBase.cpp59
-rw-r--r--lib/AST/DeclCXX.cpp38
-rw-r--r--lib/AST/DeclSerialization.cpp17
-rw-r--r--lib/Parse/ParseDecl.cpp4
-rw-r--r--lib/Parse/ParseDeclCXX.cpp27
-rw-r--r--lib/Sema/IdentifierResolver.cpp61
-rw-r--r--lib/Sema/IdentifierResolver.h17
-rw-r--r--lib/Sema/Sema.h21
-rw-r--r--lib/Sema/SemaDecl.cpp53
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--test/SemaCXX/qualified-id-lookup.cpp8
16 files changed, 549 insertions, 245 deletions
diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp
index 6681ec95f1..6836d0c6f2 100644
--- a/Driver/ASTConsumers.cpp
+++ b/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/docs/InternalsManual.html b/docs/InternalsManual.html
index 531e576758..aa96c0df40 100644
--- a/docs/InternalsManual.html
+++ b/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&lt;Item&gt; *Vector;
+ std::set&lt;Item&gt; *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/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 9ceb780172..32760f391b 100644
--- a/include/clang/AST/DeclBase.h
+++ b/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/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index d66e1a241e..6f156fa827 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/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/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index fb1d9d4c0e..096104b915 100644
--- a/include/clang/Parse/Action.h
+++ b/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/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index c6b3c53cc4..59d8a07bfd 100644
--- a/lib/AST/DeclBase.cpp
+++ b/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/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 27065a75ba..66afac8524 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/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/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp
index 68412f968a..0a298139bd 100644
--- a/lib/AST/DeclSerialization.cpp
+++ b/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);