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
This commit is contained in:
Argyrios Kyrtzidis 2008-11-09 23:41:00 +00:00
Родитель 0f84a23cc5
Коммит 5239304ff7
7 изменённых файлов: 137 добавлений и 31 удалений

Просмотреть файл

@ -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<MultipleDC*>(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<uintptr_t>(DC)) {}
virtual ~ScopedDecl();
public:
const DeclContext *getDeclContext() const { return DeclCtx; }
DeclContext *getDeclContext() { return DeclCtx; }
const DeclContext *getDeclContext() const {
if (isInSemaDC())
return reinterpret_cast<DeclContext*>(DeclCtx);
return getMultipleDC()->SemanticDC;
}
DeclContext *getDeclContext() {
return const_cast<DeclContext*>(
const_cast<const ScopedDecl*>(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<DeclContext*>(DeclCtx);
return getMultipleDC()->LexicalDC;
}
DeclContext *getLexicalDeclContext() {
return const_cast<DeclContext*>(
const_cast<const ScopedDecl*>(this)->getLexicalDeclContext());
}
void setLexicalDeclContext(DeclContext *DC);
ScopedDecl *getNext() const { return Next; }
void setNext(ScopedDecl *N) { Next = N; }

Просмотреть файл

@ -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); }

Просмотреть файл

@ -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<uintptr_t>(MDC) | 0x1;
} else {
getMultipleDC()->LexicalDC = DC;
}
}
ScopedDecl::~ScopedDecl() {
if (isOutOfSemaDC())
delete getMultipleDC();
}
//===----------------------------------------------------------------------===//
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//

Просмотреть файл

@ -145,15 +145,31 @@ void ScopedDecl::EmitInRec(Serializer& S) const {
NamedDecl::EmitInRec(S);
S.EmitPtr(getNext()); // From ScopedDecl.
S.EmitPtr(cast_or_null<Decl>(getDeclContext())); // From ScopedDecl.
S.EmitPtr(cast_or_null<Decl>(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<uintptr_t>(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<uintptr_t&>(MDC->SemanticDC), SemaDCPtrID);
D.ReadUIntPtr(reinterpret_cast<uintptr_t&>(MDC->LexicalDC), LexicalDCPtrID);
}
}
//===------------------------------------------------------------===//

Просмотреть файл

@ -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;

Просмотреть файл

@ -53,8 +53,8 @@ std::string Sema::getTypeAsString(TypeTy *Type) {
DeclContext *Sema::getContainingDC(DeclContext *DC) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))
return LexicalFileContext;
if (isa<ObjCMethodDecl>(DC))
return Context.getTranslationUnitDecl();
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(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<CXXMethodDecl>(FD))
if (isa<CXXRecordDecl>(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;
}

Просмотреть файл

@ -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;