зеркало из https://github.com/microsoft/clang-1.git
Implement Sema support for C++ nested-name-specifiers.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58916 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
751810234f
Коммит
ef6e647b8d
|
@ -310,10 +310,21 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool isFileContext() const {
|
||||
return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
bool isCXXRecord() const {
|
||||
return DeclKind == Decl::CXXRecord;
|
||||
}
|
||||
|
||||
bool Encloses(DeclContext *DC) const {
|
||||
for (; DC; DC = DC->getParent())
|
||||
if (DC == this)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const ScopedDecl *getDeclChain() const { return DeclChain; }
|
||||
ScopedDecl *getDeclChain() { return DeclChain; }
|
||||
void setDeclChain(ScopedDecl *D) { DeclChain = D; }
|
||||
|
|
|
@ -391,12 +391,14 @@ 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) {}
|
||||
isInline, PrevDecl), IsInlineDef(false) {}
|
||||
|
||||
public:
|
||||
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
|
@ -407,6 +409,10 @@ 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; }
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
|
|
|
@ -1165,6 +1165,14 @@ DIAG(err_type_defined_in_condition, ERROR,
|
|||
"types may not be defined in conditions")
|
||||
DIAG(err_typecheck_bool_condition, ERROR,
|
||||
"expression must have bool type (or be convertible to bool) ('%0' invalid)")
|
||||
DIAG(err_expected_class_or_namespace, ERROR,
|
||||
"expected a class or namespace")
|
||||
DIAG(err_invalid_declarator_scope, ERROR,
|
||||
"definition or redeclaration for '%0' not in a namespace enclosing '%1'")
|
||||
DIAG(err_invalid_declarator_in_function, ERROR,
|
||||
"definition or redeclaration for '%0' not allowed inside a function")
|
||||
DIAG(err_not_tag_in_scope, ERROR,
|
||||
"'%0' does not name a tag member in the specified scope")
|
||||
|
||||
|
||||
// assignment related diagnostics (also for argument passing, returning, etc).
|
||||
|
|
|
@ -35,7 +35,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name)
|
|||
|
||||
void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
||||
TUScope = S;
|
||||
CurContext = Context.getTranslationUnitDecl();
|
||||
PushDeclContext(Context.getTranslationUnitDecl());
|
||||
if (!PP.getLangOptions().ObjC1) return;
|
||||
|
||||
// Synthesize "typedef struct objc_selector *SEL;"
|
||||
|
@ -81,8 +81,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
|||
}
|
||||
|
||||
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
|
||||
: PP(pp), Context(ctxt), Consumer(consumer), CurContext(0), CurBlock(0),
|
||||
PackContext(0), IdResolver(pp.getLangOptions()) {
|
||||
: PP(pp), Context(ctxt), Consumer(consumer), CurContext(0),PreDeclaratorDC(0),
|
||||
CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()) {
|
||||
|
||||
// Get IdentifierInfo objects for known functions for which we
|
||||
// do extra checking.
|
||||
|
|
|
@ -109,6 +109,14 @@ 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;
|
||||
|
||||
/// CurBlock - If inside of a block definition, this contains a pointer to
|
||||
/// the active block object that represents it.
|
||||
BlockSemaInfo *CurBlock;
|
||||
|
@ -332,7 +340,7 @@ public:
|
|||
virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
|
||||
DeclTy **Elements, unsigned NumElements);
|
||||
|
||||
DeclContext *getDCParent(DeclContext *DC);
|
||||
DeclContext *getContainingDC(DeclContext *DC);
|
||||
|
||||
/// Set the current declaration context until it gets popped.
|
||||
void PushDeclContext(DeclContext *DC);
|
||||
|
@ -441,6 +449,7 @@ public:
|
|||
|
||||
/// More parsing and symbol table subroutines...
|
||||
Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
|
||||
DeclContext *LookupCtx = 0,
|
||||
bool enableLazyBuiltinCreation = true);
|
||||
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
|
||||
ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
|
||||
|
@ -773,6 +782,38 @@ public:
|
|||
SourceLocation EqualLoc,
|
||||
ExprTy *AssignExprVal);
|
||||
|
||||
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
|
||||
/// global scope ('::').
|
||||
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
|
||||
SourceLocation CCLoc);
|
||||
|
||||
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
|
||||
/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
|
||||
/// we want to resolve "bar::". 'SS' is empty or the previously parsed
|
||||
/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
|
||||
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
|
||||
/// Returns a CXXScopeTy* object representing the C++ scope.
|
||||
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdLoc,
|
||||
SourceLocation CCLoc,
|
||||
const IdentifierInfo &II);
|
||||
|
||||
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
|
||||
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
|
||||
/// After this method is called, according to [C++ 3.4.3p3], names should be
|
||||
/// looked up in the declarator-id's scope, until the declarator is parsed and
|
||||
/// ActOnCXXExitDeclaratorScope is called.
|
||||
/// The 'SS' should be a non-empty valid CXXScopeSpec.
|
||||
virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
|
||||
|
||||
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
|
||||
/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
|
||||
/// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
|
||||
/// Used to indicate that names should revert to being looked up in the
|
||||
/// defining scope.
|
||||
virtual void ActOnCXXExitDeclaratorScope(const CXXScopeSpec &SS);
|
||||
|
||||
// ParseObjCStringLiteral - Parse Objective-C string literals.
|
||||
virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
|
||||
ExprTy **Strings,
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
//===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements C++ semantic analysis for scope specifiers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Sema.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
using namespace clang;
|
||||
|
||||
|
||||
namespace {
|
||||
Decl *LookupNestedName(DeclContext *LookupCtx, bool LookInParentCtx,
|
||||
const IdentifierInfo &II, bool &IdIsUndeclared) {
|
||||
IdentifierResolver::iterator
|
||||
I = IdentifierResolver::begin(&II, LookupCtx, LookInParentCtx),
|
||||
E = IdentifierResolver::end();
|
||||
|
||||
if (I == E) {
|
||||
IdIsUndeclared = true;
|
||||
return 0;
|
||||
}
|
||||
IdIsUndeclared = false;
|
||||
|
||||
// C++ 3.4.3p1 :
|
||||
// During the lookup for a name preceding the :: scope resolution operator,
|
||||
// object, function, and enumerator names are ignored. If the name found is
|
||||
// not a class-name or namespace-name, the program is ill-formed.
|
||||
|
||||
for (; I != E; ++I) {
|
||||
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(*I)) {
|
||||
if (TD->getUnderlyingType()->isRecordType())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (((*I)->getIdentifierNamespace()&Decl::IDNS_Tag) && !isa<EnumDecl>(*I))
|
||||
break;
|
||||
}
|
||||
|
||||
return (I != E ? *I : 0);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
|
||||
/// global scope ('::').
|
||||
Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
|
||||
SourceLocation CCLoc) {
|
||||
return cast<DeclContext>(Context.getTranslationUnitDecl());
|
||||
}
|
||||
|
||||
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
|
||||
/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
|
||||
/// we want to resolve "bar::". 'SS' is empty or the previously parsed
|
||||
/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
|
||||
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
|
||||
/// Returns a CXXScopeTy* object representing the C++ scope.
|
||||
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdLoc,
|
||||
SourceLocation CCLoc,
|
||||
const IdentifierInfo &II) {
|
||||
DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
|
||||
Decl *SD;
|
||||
bool IdIsUndeclared;
|
||||
|
||||
if (DC)
|
||||
SD = LookupNestedName(DC, false/*LookInParentCtx*/, II, IdIsUndeclared);
|
||||
else
|
||||
SD = LookupNestedName(CurContext, true/*LookInParent*/, II, IdIsUndeclared);
|
||||
|
||||
if (SD) {
|
||||
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
|
||||
assert(TD->getUnderlyingType()->isRecordType() &&"Invalid Scope Decl!");
|
||||
SD = TD->getUnderlyingType()->getAsRecordType()->getDecl();
|
||||
}
|
||||
|
||||
assert((isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) &&
|
||||
"Invalid Scope Decl!");
|
||||
return cast<DeclContext>(SD);
|
||||
}
|
||||
|
||||
unsigned DiagID;
|
||||
if (!IdIsUndeclared)
|
||||
DiagID = diag::err_expected_class_or_namespace;
|
||||
else if (DC)
|
||||
DiagID = diag::err_typecheck_no_member;
|
||||
else
|
||||
DiagID = diag::err_undeclared_var_use;
|
||||
|
||||
if (DC)
|
||||
Diag(IdLoc, DiagID, II.getName(), SS.getRange());
|
||||
else
|
||||
Diag(IdLoc, DiagID, II.getName());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
|
||||
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
|
||||
/// After this method is called, according to [C++ 3.4.3p3], names should be
|
||||
/// looked up in the declarator-id's scope, until the declarator is parsed and
|
||||
/// ActOnCXXExitDeclaratorScope is called.
|
||||
/// The 'SS' should be a non-empty valid CXXScopeSpec.
|
||||
void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
|
||||
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
|
||||
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
|
||||
PreDeclaratorDC = CurContext;
|
||||
CurContext = static_cast<DeclContext*>(SS.getScopeRep());
|
||||
}
|
||||
|
||||
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
|
||||
/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
|
||||
/// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
|
||||
/// Used to indicate that names should revert to being looked up in the
|
||||
/// defining scope.
|
||||
void Sema::ActOnCXXExitDeclaratorScope(const CXXScopeSpec &SS) {
|
||||
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
|
||||
assert(CurContext == static_cast<DeclContext*>(SS.getScopeRep()) &&
|
||||
"Context imbalance!");
|
||||
CurContext = PreDeclaratorDC;
|
||||
PreDeclaratorDC = 0;
|
||||
}
|
|
@ -30,7 +30,13 @@ using namespace clang;
|
|||
|
||||
Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS) {
|
||||
Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, false);
|
||||
DeclContext *DC = 0;
|
||||
if (SS) {
|
||||
if (SS->isInvalid())
|
||||
return 0;
|
||||
DC = static_cast<DeclContext*>(SS->getScopeRep());
|
||||
}
|
||||
Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
|
||||
|
||||
if (IIDecl && (isa<TypedefDecl>(IIDecl) ||
|
||||
isa<ObjCInterfaceDecl>(IIDecl) ||
|
||||
|
@ -44,16 +50,16 @@ std::string Sema::getTypeAsString(TypeTy *Type) {
|
|||
return Ty.getAsString();
|
||||
}
|
||||
|
||||
DeclContext *Sema::getDCParent(DeclContext *DC) {
|
||||
// If CurContext is a ObjC method, getParent() will return NULL.
|
||||
if (isa<ObjCMethodDecl>(DC))
|
||||
return Context.getTranslationUnitDecl();
|
||||
|
||||
// A C++ inline method is parsed *after* the topmost class it was declared in
|
||||
// is fully parsed (it's "complete").
|
||||
// The parsing of a C++ inline method happens at the declaration context of
|
||||
// the topmost (non-nested) class it is declared in.
|
||||
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;
|
||||
|
||||
// A C++ inline method is parsed *after* the topmost class it was declared in
|
||||
// is fully parsed (it's "complete").
|
||||
// The parsing of a C++ inline method happens at the declaration context of
|
||||
// the topmost (non-nested) class it is declared in.
|
||||
assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
|
||||
DC = MD->getParent();
|
||||
while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
|
||||
|
@ -64,18 +70,25 @@ DeclContext *Sema::getDCParent(DeclContext *DC) {
|
|||
return DC;
|
||||
}
|
||||
|
||||
if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))
|
||||
return LexicalFileContext;
|
||||
|
||||
return DC->getParent();
|
||||
}
|
||||
|
||||
void Sema::PushDeclContext(DeclContext *DC) {
|
||||
assert(getDCParent(DC) == CurContext &&
|
||||
assert(getContainingDC(DC) == CurContext &&
|
||||
"The next DeclContext should be directly contained in the current one.");
|
||||
CurContext = DC;
|
||||
if (CurContext->isFileContext())
|
||||
LexicalFileContext = CurContext;
|
||||
}
|
||||
|
||||
void Sema::PopDeclContext() {
|
||||
assert(CurContext && "DeclContext imbalance!");
|
||||
CurContext = getDCParent(CurContext);
|
||||
CurContext = getContainingDC(CurContext);
|
||||
if (CurContext->isFileContext())
|
||||
LexicalFileContext = CurContext;
|
||||
}
|
||||
|
||||
/// Add this decl to the scope shadowed decl chains.
|
||||
|
@ -180,18 +193,20 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
|
|||
|
||||
/// LookupDecl - Look up the inner-most declaration in the specified
|
||||
/// namespace.
|
||||
Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI,
|
||||
Scope *S, bool enableLazyBuiltinCreation) {
|
||||
Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
|
||||
DeclContext *LookupCtx, bool enableLazyBuiltinCreation) {
|
||||
if (II == 0) return 0;
|
||||
unsigned NS = NSI;
|
||||
if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary))
|
||||
NS |= Decl::IDNS_Tag;
|
||||
|
||||
IdentifierResolver::iterator
|
||||
I = LookupCtx ? IdResolver.begin(II, LookupCtx, false/*LookInParentCtx*/) :
|
||||
IdResolver.begin(II, CurContext, true/*LookInParentCtx*/);
|
||||
// Scan up the scope chain looking for a decl that matches this identifier
|
||||
// that is in the appropriate namespace. This search should not take long, as
|
||||
// shadowing of names is uncommon, and deep shadowing is extremely uncommon.
|
||||
for (IdentifierResolver::iterator
|
||||
I = IdResolver.begin(II, CurContext), E = IdResolver.end(); I != E; ++I)
|
||||
for (; I != IdResolver.end(); ++I)
|
||||
if ((*I)->getIdentifierNamespace() & NS)
|
||||
return *I;
|
||||
|
||||
|
@ -199,7 +214,8 @@ Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI,
|
|||
// corresponds to a compiler builtin, create the decl object for the builtin
|
||||
// now, injecting it into translation unit scope, and return it.
|
||||
if (NS & Decl::IDNS_Ordinary) {
|
||||
if (enableLazyBuiltinCreation) {
|
||||
if (enableLazyBuiltinCreation &&
|
||||
(LookupCtx == 0 || isa<TranslationUnitDecl>(LookupCtx))) {
|
||||
// If this is a builtin on this (or all) targets, create the decl.
|
||||
if (unsigned BuiltinID = II->getBuiltinID())
|
||||
return LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S);
|
||||
|
@ -749,11 +765,45 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
while ((S->getFlags() & Scope::DeclScope) == 0)
|
||||
S = S->getParent();
|
||||
|
||||
// See if this is a redefinition of a variable in the same scope.
|
||||
Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S);
|
||||
DeclContext *DC;
|
||||
Decl *PrevDecl;
|
||||
ScopedDecl *New;
|
||||
bool InvalidDecl = false;
|
||||
|
||||
// See if this is a redefinition of a variable in the same scope.
|
||||
if (!D.getCXXScopeSpec().isSet()) {
|
||||
DC = CurContext;
|
||||
PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S);
|
||||
} else { // Something like "int foo::x;"
|
||||
DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep());
|
||||
PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S, DC);
|
||||
|
||||
// C++ 7.3.1.2p2:
|
||||
// Members (including explicit specializations of templates) of a named
|
||||
// namespace can also be defined outside that namespace by explicit
|
||||
// qualification of the name being defined, provided that the entity being
|
||||
// defined was already declared in the namespace and the definition appears
|
||||
// after the point of declaration in a namespace that encloses the
|
||||
// declarations namespace.
|
||||
//
|
||||
if (PrevDecl == 0) {
|
||||
// No previous declaration in the qualifying scope.
|
||||
Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member,
|
||||
II->getName(), D.getCXXScopeSpec().getRange());
|
||||
} else if (!CurContext->Encloses(DC)) {
|
||||
// The qualifying scope doesn't enclose the original declaration.
|
||||
// Emit diagnostic based on current scope.
|
||||
SourceLocation L = D.getIdentifierLoc();
|
||||
SourceRange R = D.getCXXScopeSpec().getRange();
|
||||
if (isa<FunctionDecl>(CurContext)) {
|
||||
Diag(L, diag::err_invalid_declarator_in_function, II->getName(), R);
|
||||
} else {
|
||||
Diag(L, diag::err_invalid_declarator_scope, II->getName(),
|
||||
cast<NamedDecl>(DC)->getName(), R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In C++, the previous declaration we find might be a tag type
|
||||
// (class or enum). In this case, the new declaration will hide the
|
||||
// tag type.
|
||||
|
@ -775,7 +825,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
ProcessDeclAttributes(NewTD, D);
|
||||
// Merge the decl with the existing one if appropriate. If the decl is
|
||||
// in an outer scope, it isn't the same thing.
|
||||
if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)) {
|
||||
if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
|
||||
NewTD = MergeTypeDefDecl(NewTD, PrevDecl);
|
||||
if (NewTD == 0) return 0;
|
||||
}
|
||||
|
@ -812,14 +862,14 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
FunctionDecl *NewFD;
|
||||
if (D.getKind() == Declarator::DK_Constructor) {
|
||||
// This is a C++ constructor declaration.
|
||||
assert(CurContext->isCXXRecord() &&
|
||||
assert(DC->isCXXRecord() &&
|
||||
"Constructors can only be declared in a member context");
|
||||
|
||||
bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC);
|
||||
|
||||
// Create the new declaration
|
||||
NewFD = CXXConstructorDecl::Create(Context,
|
||||
cast<CXXRecordDecl>(CurContext),
|
||||
cast<CXXRecordDecl>(DC),
|
||||
D.getIdentifierLoc(), II, R,
|
||||
isExplicit, isInline,
|
||||
/*isImplicitlyDeclared=*/false);
|
||||
|
@ -828,11 +878,11 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
NewFD->setInvalidDecl();
|
||||
} else if (D.getKind() == Declarator::DK_Destructor) {
|
||||
// This is a C++ destructor declaration.
|
||||
if (CurContext->isCXXRecord()) {
|
||||
if (DC->isCXXRecord()) {
|
||||
bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC);
|
||||
|
||||
NewFD = CXXDestructorDecl::Create(Context,
|
||||
cast<CXXRecordDecl>(CurContext),
|
||||
cast<CXXRecordDecl>(DC),
|
||||
D.getIdentifierLoc(), II, R,
|
||||
isInline,
|
||||
/*isImplicitlyDeclared=*/false);
|
||||
|
@ -843,14 +893,14 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
|
||||
// Create a FunctionDecl to satisfy the function definition parsing
|
||||
// code path.
|
||||
NewFD = FunctionDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
||||
NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
|
||||
II, R, SC, isInline, LastDeclarator,
|
||||
// FIXME: Move to DeclGroup...
|
||||
D.getDeclSpec().getSourceRange().getBegin());
|
||||
NewFD->setInvalidDecl();
|
||||
}
|
||||
} else if (D.getKind() == Declarator::DK_Conversion) {
|
||||
if (!CurContext->isCXXRecord()) {
|
||||
if (!DC->isCXXRecord()) {
|
||||
Diag(D.getIdentifierLoc(),
|
||||
diag::err_conv_function_not_member);
|
||||
return 0;
|
||||
|
@ -858,21 +908,21 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
|
||||
|
||||
NewFD = CXXConversionDecl::Create(Context,
|
||||
cast<CXXRecordDecl>(CurContext),
|
||||
cast<CXXRecordDecl>(DC),
|
||||
D.getIdentifierLoc(), II, R,
|
||||
isInline, isExplicit);
|
||||
|
||||
if (isInvalidDecl)
|
||||
NewFD->setInvalidDecl();
|
||||
}
|
||||
} else if (CurContext->isCXXRecord()) {
|
||||
} else if (DC->isCXXRecord()) {
|
||||
// This is a C++ method declaration.
|
||||
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
|
||||
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
|
||||
D.getIdentifierLoc(), II, R,
|
||||
(SC == FunctionDecl::Static), isInline,
|
||||
LastDeclarator);
|
||||
} else {
|
||||
NewFD = FunctionDecl::Create(Context, CurContext,
|
||||
NewFD = FunctionDecl::Create(Context, DC,
|
||||
D.getIdentifierLoc(),
|
||||
II, R, SC, isInline, LastDeclarator,
|
||||
// FIXME: Move to DeclGroup...
|
||||
|
@ -943,7 +993,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
||||
for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
|
||||
ArgType != FT->arg_type_end(); ++ArgType) {
|
||||
Params.push_back(ParmVarDecl::Create(Context, CurContext,
|
||||
Params.push_back(ParmVarDecl::Create(Context, DC,
|
||||
SourceLocation(), 0,
|
||||
*ArgType, VarDecl::None,
|
||||
0, 0));
|
||||
|
@ -972,7 +1022,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
// Merge the decl with the existing one if appropriate. Since C functions
|
||||
// are in a flat namespace, make sure we consider decls in outer scopes.
|
||||
if (PrevDecl &&
|
||||
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, CurContext, S))) {
|
||||
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
|
||||
bool Redeclaration = false;
|
||||
|
||||
// If C++, determine whether NewFD is an overload of PrevDecl or
|
||||
|
@ -1046,10 +1096,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
case DeclSpec::SCS_register: SC = VarDecl::Register; break;
|
||||
case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
|
||||
}
|
||||
if (CurContext->isCXXRecord()) {
|
||||
if (DC->isCXXRecord()) {
|
||||
assert(SC == VarDecl::Static && "Invalid storage class for member!");
|
||||
// This is a static data member for a C++ class.
|
||||
NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
|
||||
NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(DC),
|
||||
D.getIdentifierLoc(), II,
|
||||
R, LastDeclarator);
|
||||
} else {
|
||||
|
@ -1063,7 +1113,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
InvalidDecl = true;
|
||||
}
|
||||
}
|
||||
NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
||||
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
|
||||
II, R, SC, LastDeclarator,
|
||||
// FIXME: Move to DeclGroup...
|
||||
D.getDeclSpec().getSourceRange().getBegin());
|
||||
|
@ -1090,7 +1140,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
}
|
||||
// Merge the decl with the existing one if appropriate. If the decl is
|
||||
// in an outer scope, it isn't the same thing.
|
||||
if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)) {
|
||||
if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
|
||||
NewVD = MergeVarDecl(NewVD, PrevDecl);
|
||||
if (NewVD == 0) return 0;
|
||||
}
|
||||
|
@ -1824,6 +1874,7 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) {
|
|||
/// to introduce parameters into function prototype scope.
|
||||
Sema::DeclTy *
|
||||
Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
|
||||
// FIXME: disallow CXXScopeSpec for param declarators.
|
||||
const DeclSpec &DS = D.getDeclSpec();
|
||||
|
||||
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
|
||||
|
@ -1953,6 +2004,10 @@ 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
|
||||
|
@ -2083,6 +2138,53 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
|
|||
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
|
||||
case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break;
|
||||
}
|
||||
|
||||
if (Name && SS.isNotEmpty()) {
|
||||
DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
|
||||
if (DC == 0) {
|
||||
// Invalid C++ scope specifier.
|
||||
Name = 0;
|
||||
goto CreateNewDecl;
|
||||
}
|
||||
|
||||
TagDecl *PrevDecl =
|
||||
dyn_cast_or_null<TagDecl>(LookupDecl(Name, Decl::IDNS_Tag, S, DC));
|
||||
if (PrevDecl == 0) {
|
||||
// No tag member found.
|
||||
Diag(NameLoc, diag::err_not_tag_in_scope, Name->getName(),
|
||||
SS.getRange());
|
||||
Name = 0;
|
||||
goto CreateNewDecl;
|
||||
}
|
||||
|
||||
if (PrevDecl->getTagKind() != Kind) {
|
||||
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
|
||||
Diag(PrevDecl->getLocation(), diag::err_previous_use);
|
||||
// Recover by making this an anonymous redefinition.
|
||||
Name = 0;
|
||||
goto CreateNewDecl;
|
||||
}
|
||||
|
||||
// If this is a use or a forward declaration, we're good.
|
||||
if (TK != TK_Definition)
|
||||
return PrevDecl;
|
||||
|
||||
// Diagnose attempts to redefine a tag.
|
||||
if (PrevDecl->isDefinition()) {
|
||||
Diag(NameLoc, diag::err_redefinition, Name->getName());
|
||||
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
||||
// If this is a redefinition, recover by making this struct be
|
||||
// anonymous, which will make any later references get the previous
|
||||
// definition.
|
||||
Name = 0;
|
||||
goto CreateNewDecl;
|
||||
}
|
||||
|
||||
// Okay, this is definition of a previously declared or referenced
|
||||
// tag. Move the location of the decl to be the definition site.
|
||||
PrevDecl->setLocation(NameLoc);
|
||||
return PrevDecl;
|
||||
}
|
||||
|
||||
// Two code paths: a new one for structs/unions/classes where we create
|
||||
// separate decls for forward declarations, and an old (eventually to
|
||||
|
@ -2090,6 +2192,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
|
|||
if (Kind != TagDecl::TK_enum)
|
||||
return ActOnTagStruct(S, Kind, TK, KWLoc, Name, NameLoc, Attr);
|
||||
|
||||
{
|
||||
|
||||
// If this is a named struct, check to see if there was a previous forward
|
||||
// declaration or definition.
|
||||
// Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
|
||||
|
@ -2147,6 +2251,10 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // subscope in which an already declared tag is handled.
|
||||
|
||||
CreateNewDecl:
|
||||
|
||||
// If there is an identifier, use the location of the identifier as the
|
||||
// location of the decl, otherwise use the location of the struct/union
|
||||
|
|
|
@ -264,7 +264,14 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
|
|||
/// the innermost class.
|
||||
bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
|
||||
const CXXScopeSpec *SS) {
|
||||
if (CXXRecordDecl *CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext))
|
||||
CXXRecordDecl *CurDecl;
|
||||
if (SS) {
|
||||
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
|
||||
CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
|
||||
} else
|
||||
CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
|
||||
|
||||
if (CurDecl)
|
||||
return &II == CurDecl->getIdentifier();
|
||||
else
|
||||
return false;
|
||||
|
@ -1253,7 +1260,7 @@ Sema::DeclTy *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
|||
// in that declarative region, it is treated as an original-namespace-name.
|
||||
|
||||
Decl *PrevDecl =
|
||||
LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope,
|
||||
LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0,
|
||||
/*enableLazyBuiltinCreation=*/false);
|
||||
|
||||
if (PrevDecl && isDeclInScope(PrevDecl, CurContext, DeclRegionScope)) {
|
||||
|
|
|
@ -335,12 +335,21 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
|
|||
/// ActOnIdentifierExpr - The parser read an identifier in expression context,
|
||||
/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
|
||||
/// identifier is used in a function call context.
|
||||
/// LookupCtx is only used for a C++ qualified-id (foo::bar) to indicate the
|
||||
/// class or namespace that the identifier must be a member of.
|
||||
Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
IdentifierInfo &II,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS) {
|
||||
// Could be enum-constant, value decl, instance variable, etc.
|
||||
Decl *D = LookupDecl(&II, Decl::IDNS_Ordinary, S);
|
||||
Decl *D;
|
||||
if (SS && !SS->isEmpty()) {
|
||||
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
|
||||
if (DC == 0)
|
||||
return true;
|
||||
D = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC);
|
||||
} else
|
||||
D = LookupDecl(&II, Decl::IDNS_Ordinary, S);
|
||||
|
||||
// If this reference is in an Objective-C method, then ivar lookup happens as
|
||||
// well.
|
||||
|
@ -378,7 +387,11 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
|||
else {
|
||||
// If this name wasn't predeclared and if this is not a function call,
|
||||
// diagnose the problem.
|
||||
return Diag(Loc, diag::err_undeclared_var_use, II.getName());
|
||||
if (SS && !SS->isEmpty())
|
||||
return Diag(Loc, diag::err_typecheck_no_member,
|
||||
II.getName(), SS->getRange());
|
||||
else
|
||||
return Diag(Loc, diag::err_undeclared_var_use, II.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
namespace A {
|
||||
struct C {
|
||||
static int cx;
|
||||
};
|
||||
int ax;
|
||||
void Af();
|
||||
}
|
||||
|
||||
A:: ; // expected-error {{expected unqualified-id}}
|
||||
::A::ax::undef ex3; // expected-error {{expected a class or namespace}} expected-error {{expected '=', ',', ';', 'asm', or '__attribute__' after declarator}}
|
||||
A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{expected '=', ',', ';', 'asm', or '__attribute__' after declarator}}
|
||||
|
||||
class C2 {
|
||||
void m();
|
||||
int x;
|
||||
};
|
||||
|
||||
void C2::m() {
|
||||
x = 0;
|
||||
}
|
||||
|
||||
namespace B {
|
||||
void ::A::Af() {} // expected-error {{definition or redeclaration for 'Af' not in a namespace enclosing 'A'}}
|
||||
}
|
||||
|
||||
void f1() {
|
||||
void A::Af(); // expected-error {{definition or redeclaration for 'Af' not allowed inside a function}}
|
||||
}
|
||||
|
||||
void f2() {
|
||||
A:: ; // expected-error {{expected unqualified-id}}
|
||||
A::C::undef = 0; // expected-error {{no member named 'undef'}}
|
||||
::A::C::cx = 0;
|
||||
int x = ::A::ax = A::C::cx;
|
||||
x = sizeof(A::C);
|
||||
x = sizeof(::A::C::cx);
|
||||
}
|
||||
|
||||
A::C c1;
|
||||
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}}
|
||||
|
||||
void f3() {
|
||||
N::x = 0; // expected-error {{use of undeclared identifier 'N'}}
|
||||
int N;
|
||||
N::x = 0; // expected-error {{expected a class or namespace}}
|
||||
{ int A; A::ax = 0; }
|
||||
{ enum A {}; A::ax = 0; }
|
||||
{ enum A { A }; A::ax = 0; }
|
||||
{ typedef int A; A::ax = 0; }
|
||||
{ typedef int A(); A::ax = 0; }
|
||||
{ typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}}
|
||||
{ typedef A::C A; A::cx = 0; }
|
||||
}
|
Загрузка…
Ссылка в новой задаче