From: Argyrios Kyrtzidis Date: Sun, 9 Nov 2008 23:41:00 +0000 (+0000) Subject: Introduce ScopedDecl::getLexicalDeclContext() which is different from ScopedDecl... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5239304ff761b8b03eefb772bd5d830a9b9f1aea;p=clang Introduce ScopedDecl::getLexicalDeclContext() which is different from ScopedDecl::getDeclContext() when there are nested-names. e.g.: namespace A { void f(); // SemanticDC (getDeclContext) == LexicalDC (getLexicalDeclContext) == 'namespace A' } void A::f(); // SemanticDC == namespace 'A' // LexicalDC == global namespace git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58948 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 6348ce66e2..d7e25357c5 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -92,16 +92,72 @@ class ScopedDecl : public NamedDecl { /// ScopedDecl *Next; - DeclContext *DeclCtx; + /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. + /// For declarations that don't contain C++ scope specifiers, it contains + /// the DeclContext where the ScopedDecl was declared. + /// For declarations with C++ scope specifiers, it contains a MultipleDC* + /// with the context where it semantically belongs (SemanticDC) and the + /// context where it was lexically declared (LexicalDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + uintptr_t DeclCtx; + + struct MultipleDC { + DeclContext *SemanticDC; + DeclContext *LexicalDC; + }; + + inline bool isInSemaDC() const { return (DeclCtx & 0x1) == 0; } + inline bool isOutOfSemaDC() const { return (DeclCtx & 0x1) != 0; } + inline MultipleDC *getMultipleDC() const { + return reinterpret_cast(DeclCtx & ~0x1); + } protected: ScopedDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ScopedDecl *PrevDecl) - : NamedDecl(DK, L, Id), NextDeclarator(PrevDecl), Next(0), DeclCtx(DC) {} + : NamedDecl(DK, L, Id), NextDeclarator(PrevDecl), Next(0), + DeclCtx(reinterpret_cast(DC)) {} + + virtual ~ScopedDecl(); public: - const DeclContext *getDeclContext() const { return DeclCtx; } - DeclContext *getDeclContext() { return DeclCtx; } + const DeclContext *getDeclContext() const { + if (isInSemaDC()) + return reinterpret_cast(DeclCtx); + return getMultipleDC()->SemanticDC; + } + DeclContext *getDeclContext() { + return const_cast( + const_cast(this)->getDeclContext()); + } + + /// getLexicalDeclContext - The declaration context where this ScopedDecl was + /// lexically declared (LexicalDC). May be different from + /// getDeclContext() (SemanticDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + const DeclContext *getLexicalDeclContext() const { + if (isInSemaDC()) + return reinterpret_cast(DeclCtx); + return getMultipleDC()->LexicalDC; + } + DeclContext *getLexicalDeclContext() { + return const_cast( + const_cast(this)->getLexicalDeclContext()); + } + + void setLexicalDeclContext(DeclContext *DC); ScopedDecl *getNext() const { return Next; } void setNext(ScopedDecl *N) { Next = N; } diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index d8e7444be1..26ccb62bdc 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -391,14 +391,12 @@ protected: /// CXXMethodDecl - Represents a static or instance method of a /// struct/union/class. class CXXMethodDecl : public FunctionDecl { - bool IsInlineDef : 1; - protected: CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, QualType T, bool isStatic, bool isInline, ScopedDecl *PrevDecl) : FunctionDecl(DK, RD, L, Id, T, (isStatic ? Static : None), - isInline, PrevDecl), IsInlineDef(false) {} + isInline, PrevDecl) {} public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, @@ -409,9 +407,9 @@ public: bool isStatic() const { return getStorageClass() == Static; } bool isInstance() const { return !isStatic(); } - bool isOutOfLineDefinition() const { return !isInlineDefinition(); } - bool isInlineDefinition() const { return IsInlineDef; } - void setInlineDefinition(bool flag) { IsInlineDef = flag; } + bool isOutOfLineDefinition() const { + return getLexicalDeclContext() != getDeclContext(); + } void setAccess(AccessSpecifier AS) { Access = AS; } AccessSpecifier getAccess() const { return AccessSpecifier(Access); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index b0fe4d1b14..fa5e9ce36e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -139,6 +139,29 @@ const char *NamedDecl::getName() const { return ""; } +//===----------------------------------------------------------------------===// +// ScopedDecl Implementation +//===----------------------------------------------------------------------===// + +void ScopedDecl::setLexicalDeclContext(DeclContext *DC) { + if (DC == getLexicalDeclContext()) + return; + + if (isInSemaDC()) { + MultipleDC *MDC = new MultipleDC(); + MDC->SemanticDC = getDeclContext(); + MDC->LexicalDC = DC; + DeclCtx = reinterpret_cast(MDC) | 0x1; + } else { + getMultipleDC()->LexicalDC = DC; + } +} + +ScopedDecl::~ScopedDecl() { + if (isOutOfSemaDC()) + delete getMultipleDC(); +} + //===----------------------------------------------------------------------===// // FunctionDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index 34066a5039..04cb71983b 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -145,15 +145,31 @@ void ScopedDecl::EmitInRec(Serializer& S) const { NamedDecl::EmitInRec(S); S.EmitPtr(getNext()); // From ScopedDecl. S.EmitPtr(cast_or_null(getDeclContext())); // From ScopedDecl. + S.EmitPtr(cast_or_null(getLexicalDeclContext())); // From ScopedDecl. } void ScopedDecl::ReadInRec(Deserializer& D, ASTContext& C) { NamedDecl::ReadInRec(D, C); D.ReadPtr(Next); // From ScopedDecl. - - assert(DeclCtx == 0); // Allow back-patching. Observe that we register - D.ReadPtr(DeclCtx); // the variable of the *object* for back-patching. - // Its actual value will get filled in later. + + assert(DeclCtx == 0); + + const SerializedPtrID &SemaDCPtrID = D.ReadPtrID(); + const SerializedPtrID &LexicalDCPtrID = D.ReadPtrID(); + + if (SemaDCPtrID == LexicalDCPtrID) { + // Allow back-patching. Observe that we register the variable of the + // *object* for back-patching. Its actual value will get filled in later. + D.ReadUIntPtr(DeclCtx, SemaDCPtrID); + } + else { + MultipleDC *MDC = new MultipleDC(); + DeclCtx = reinterpret_cast(MDC) | 0x1; + // Allow back-patching. Observe that we register the variable of the + // *object* for back-patching. Its actual value will get filled in later. + D.ReadUIntPtr(reinterpret_cast(MDC->SemanticDC), SemaDCPtrID); + D.ReadUIntPtr(reinterpret_cast(MDC->LexicalDC), LexicalDCPtrID); + } } //===------------------------------------------------------------===// diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 178ab13f16..d7518e0aa7 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -109,10 +109,6 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; - /// LexicalFileContext - The current lexical file declaration context, - /// the translation unit or a namespace. - DeclContext *LexicalFileContext; - /// PreDeclaratorDC - Keeps the declaration context before switching to the /// context of a declarator's nested-name-specifier. DeclContext *PreDeclaratorDC; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index cae05a365c..6c71d50895 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -53,8 +53,8 @@ std::string Sema::getTypeAsString(TypeTy *Type) { DeclContext *Sema::getContainingDC(DeclContext *DC) { if (CXXMethodDecl *MD = dyn_cast(DC)) { // A C++ out-of-line method will return to the file declaration context. - if (!MD->isInlineDefinition()) - return LexicalFileContext; + if (MD->isOutOfLineDefinition()) + return MD->getLexicalDeclContext(); // A C++ inline method is parsed *after* the topmost class it was declared in // is fully parsed (it's "complete"). @@ -70,25 +70,24 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { return DC; } - if (isa(DC) || isa(DC)) - return LexicalFileContext; + if (isa(DC)) + return Context.getTranslationUnitDecl(); + + if (ScopedDecl *SD = dyn_cast(DC)) + return SD->getLexicalDeclContext(); return DC->getParent(); } void Sema::PushDeclContext(DeclContext *DC) { assert(getContainingDC(DC) == CurContext && - "The next DeclContext should be directly contained in the current one."); + "The next DeclContext should be lexically contained in the current one."); CurContext = DC; - if (CurContext->isFileContext()) - LexicalFileContext = CurContext; } void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); CurContext = getContainingDC(CurContext); - if (CurContext->isFileContext()) - LexicalFileContext = CurContext; } /// Add this decl to the scope shadowed decl chains. @@ -1147,6 +1146,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { New = NewVD; } + // Set the lexical context. If the declarator has a C++ scope specifier, the + // lexical context will be different from the semantic context. + New->setLexicalDeclContext(CurContext); + // If this has an identifier, add it to the scope stack. if (II) PushOnScopeChains(New, S); @@ -2004,10 +2007,6 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { Diag(Definition->getLocation(), diag::err_previous_definition); } - if (CXXMethodDecl *MD = dyn_cast(FD)) - if (isa(CurContext)) - MD->setInlineDefinition(true); - PushDeclContext(FD); // Check the validity of our function parameters @@ -2267,6 +2266,11 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, if (Attr) ProcessDeclAttributeList(New, Attr); + + // 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); + return New; } @@ -2421,6 +2425,10 @@ Sema::DeclTy *Sema::ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK, if (Attr) ProcessDeclAttributeList(New, Attr); + // 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); + return New; } diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index bbca04cd9a..cf0500dffe 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -42,6 +42,15 @@ struct A::C c2; struct S : public A::C {}; struct A::undef; // expected-error {{'undef' does not name a tag member in the specified scope}} +namespace A2 { + typedef int INT; + struct RC; +} + +struct A2::RC { + INT x; +}; + void f3() { N::x = 0; // expected-error {{use of undeclared identifier 'N'}} int N;