aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2009-12-15 18:49:47 +0000
commit34d02d0b37f16015f317a935c48ce8b7b64ae77b (patch)
tree2fd5819f49caecc5f520219b6b9254fe94ebb138 /lib/Sema/SemaDeclCXX.cpp
parent1569ce68681d909594d64f9b056d71f5dd7563bf (diff)
downloadsrc-34d02d0b37f16015f317a935c48ce8b7b64ae77b.tar.gz
src-34d02d0b37f16015f317a935c48ce8b7b64ae77b.zip
Notes
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1104
1 files changed, 894 insertions, 210 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f161cb5546a2..228a716ca483 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,11 +12,14 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Parse/DeclSpec.h"
@@ -482,24 +485,47 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
assert(BaseDecl && "Base type is not incomplete, but has no definition");
CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");
- if (!CXXBaseDecl->isEmpty())
- Class->setEmpty(false);
- if (CXXBaseDecl->isPolymorphic())
- Class->setPolymorphic(true);
+
// C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases.
if (CXXBaseDecl->hasAttr<FinalAttr>()) {
Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString();
- Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl)
- << BaseType.getAsString();
+ Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl)
+ << BaseType;
return 0;
}
+ SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual);
+
+ // Create the base specifier.
+ // FIXME: Allocate via ASTContext?
+ return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
+ Class->getTagKind() == RecordDecl::TK_class,
+ Access, BaseType);
+}
+
+void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class,
+ const CXXRecordDecl *BaseClass,
+ bool BaseIsVirtual) {
+ // A class with a non-empty base class is not empty.
+ // FIXME: Standard ref?
+ if (!BaseClass->isEmpty())
+ Class->setEmpty(false);
+
+ // C++ [class.virtual]p1:
+ // A class that [...] inherits a virtual function is called a polymorphic
+ // class.
+ if (BaseClass->isPolymorphic())
+ Class->setPolymorphic(true);
+
// C++ [dcl.init.aggr]p1:
// An aggregate is [...] a class with [...] no base classes [...].
Class->setAggregate(false);
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class...
Class->setPOD(false);
- if (Virtual) {
+ if (BaseIsVirtual) {
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
Class->setHasTrivialConstructor(false);
@@ -521,33 +547,27 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// C++ [class.ctor]p5:
// A constructor is trivial if all the direct base classes of its
// class have trivial constructors.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
+ if (!BaseClass->hasTrivialConstructor())
Class->setHasTrivialConstructor(false);
// C++ [class.copy]p6:
// A copy constructor is trivial if all the direct base classes of its
// class have trivial copy constructors.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
+ if (!BaseClass->hasTrivialCopyConstructor())
Class->setHasTrivialCopyConstructor(false);
// C++ [class.copy]p11:
// A copy assignment operator is trivial if all the direct base classes
// of its class have trivial copy assignment operators.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
+ if (!BaseClass->hasTrivialCopyAssignment())
Class->setHasTrivialCopyAssignment(false);
}
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
- if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
+ if (!BaseClass->hasTrivialDestructor())
Class->setHasTrivialDestructor(false);
-
- // Create the base specifier.
- // FIXME: Allocate via ASTContext?
- return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
- Access, BaseType);
}
/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
@@ -976,19 +996,26 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (Member)
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
- RParenLoc);
+ LParenLoc, RParenLoc);
}
// It didn't name a member, so see if it names a class.
- TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy
- : getTypeName(*MemberOrBase, IdLoc, S, &SS);
- if (!BaseTy)
+ QualType BaseType;
+
+ TypeSourceInfo *TInfo = 0;
+ if (TemplateTypeTy)
+ BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
+ else
+ BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc,
+ S, &SS));
+ if (BaseType.isNull())
return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
- QualType BaseType = GetTypeFromParser(BaseTy);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc);
- return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc,
- RParenLoc, ClassDecl);
+ return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs,
+ LParenLoc, RParenLoc, ClassDecl);
}
/// Checks an initializer expression for use of uninitialized fields, such as
@@ -1037,6 +1064,7 @@ static bool InitExprContainsUninitializedFields(const Stmt* S,
Sema::MemInitResult
Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
unsigned NumArgs, SourceLocation IdLoc,
+ SourceLocation LParenLoc,
SourceLocation RParenLoc) {
// FIXME: CXXBaseOrMemberInitializer should only contain a single
// subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
@@ -1081,7 +1109,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
NumArgs),
IdLoc,
SourceRange(IdLoc, RParenLoc),
- Member->getDeclName(), IK_Direct,
+ Member->getDeclName(),
+ InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc),
ConstructorArgs);
if (C) {
@@ -1118,22 +1147,25 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
ExprTemporaries.clear();
// FIXME: Perform direct initialization of the member.
- return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args,
- NumArgs, C, IdLoc, RParenLoc);
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ C, LParenLoc, (Expr **)Args,
+ NumArgs, RParenLoc);
}
Sema::MemInitResult
-Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
- unsigned NumArgs, SourceLocation IdLoc,
- SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) {
+Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation LParenLoc, SourceLocation RParenLoc,
+ CXXRecordDecl *ClassDecl) {
bool HasDependentArg = false;
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
+ SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
if (!BaseType->isDependentType()) {
if (!BaseType->isRecordType())
- return Diag(IdLoc, diag::err_base_init_does_not_name_class)
- << BaseType << SourceRange(IdLoc, RParenLoc);
+ return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
// C++ [class.base.init]p2:
// [...] Unless the mem-initializer-id names a nonstatic data
@@ -1179,16 +1211,16 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
// a direct non-virtual base class and an inherited virtual base
// class, the mem-initializer is ill-formed.
if (DirectBaseSpec && VirtualBaseSpec)
- return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << SourceRange(IdLoc, RParenLoc);
+ return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
// C++ [base.class.init]p2:
// Unless the mem-initializer-id names a nonstatic data membeer of the
// constructor's class ot a direst or virtual base of that class, the
// mem-initializer is ill-formed.
if (!DirectBaseSpec && !VirtualBaseSpec)
- return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << SourceRange(IdLoc, RParenLoc);
+ return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << BaseTInfo->getTypeLoc().getSourceRange();
}
CXXConstructorDecl *C = 0;
@@ -1200,8 +1232,10 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
C = PerformInitializationByConstructor(BaseType,
MultiExprArg(*this,
(void**)Args, NumArgs),
- IdLoc, SourceRange(IdLoc, RParenLoc),
- Name, IK_Direct,
+ BaseLoc,
+ SourceRange(BaseLoc, RParenLoc),
+ Name,
+ InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc),
ConstructorArgs);
if (C) {
// Take over the constructor arguments as our own.
@@ -1214,8 +1248,9 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
// subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
ExprTemporaries.clear();
- return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
- NumArgs, C, IdLoc, RParenLoc);
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C,
+ LParenLoc, (Expr **)Args,
+ NumArgs, RParenLoc);
}
bool
@@ -1277,14 +1312,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
}
else {
CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
if (!Ctor) {
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 0 << VBase->getType();
- Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl)
+ Diag(VBaseDecl->getLocation(), diag::note_previous_decl)
<< Context.getTagDeclType(VBaseDecl);
HadError = true;
continue;
@@ -1298,13 +1333,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
// FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if
+ // necessary.
+ // FIXME: Is there any better source-location information we can give?
ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(VBase->getType(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(), Ctor,
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(VBase->getType(),
+ SourceLocation()),
+ Ctor,
SourceLocation(),
+ CtorArgs.takeAs<Expr>(),
+ CtorArgs.size(),
SourceLocation());
AllToInit.push_back(Member);
}
@@ -1332,7 +1372,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 0 << Base->getType();
- Diag(BaseDecl->getLocation(), diag::note_previous_class_decl)
+ Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< Context.getTagDeclType(BaseDecl);
HadError = true;
continue;
@@ -1346,13 +1386,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
// FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if
+ // necessary.
+ // FIXME: Is there any better source-location information we can give?
ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(Base->getType(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(), Ctor,
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(Base->getType(),
+ SourceLocation()),
+ Ctor,
SourceLocation(),
+ CtorArgs.takeAs<Expr>(),
+ CtorArgs.size(),
SourceLocation());
AllToInit.push_back(Member);
}
@@ -1399,7 +1444,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag(Field->getLocation(), diag::note_field_decl);
- Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl)
+ Diag(RT->getDecl()->getLocation(), diag::note_previous_decl)
<< Context.getTagDeclType(RT->getDecl());
HadError = true;
continue;
@@ -1427,9 +1472,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
// subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs<Expr>(),
- CtorArgs.size(), Ctor,
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ *Field, SourceLocation(),
+ Ctor,
SourceLocation(),
+ CtorArgs.takeAs<Expr>(),
+ CtorArgs.size(),
SourceLocation());
AllToInit.push_back(Member);
@@ -1537,13 +1585,15 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
if (FieldDecl *Field = Member->getMember())
Diag(Member->getSourceLocation(),
diag::error_multiple_mem_initialization)
- << Field->getNameAsString();
+ << Field->getNameAsString()
+ << Member->getSourceRange();
else {
Type *BaseClass = Member->getBaseClass();
assert(BaseClass && "ActOnMemInitializers - neither field or base");
Diag(Member->getSourceLocation(),
diag::error_multiple_base_initialization)
- << QualType(BaseClass, 0);
+ << QualType(BaseClass, 0)
+ << Member->getSourceRange();
}
Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
<< 0;
@@ -1920,6 +1970,28 @@ namespace {
};
}
+/// \brief Perform semantic checks on a class definition that has been
+/// completing, introducing implicitly-declared members, checking for
+/// abstract types, etc.
+void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
+ if (!Record || Record->isInvalidDecl())
+ return;
+
+ if (!Record->isAbstract()) {
+ // Collect all the pure virtual methods and see if this is an abstract
+ // class after all.
+ PureVirtualMethodCollector Collector(Context, Record);
+ if (!Collector.empty())
+ Record->setAbstract(true);
+ }
+
+ if (Record->isAbstract())
+ (void)AbstractClassUsageDiagnoser(*this, Record);
+
+ if (!Record->isDependentType() && !Record->isInvalidDecl())
+ AddImplicitlyDeclaredMembersToClass(Record);
+}
+
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -1928,24 +2000,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
return;
AdjustDeclIfTemplate(TagDecl);
+
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
- CXXRecordDecl *RD = cast<CXXRecordDecl>(TagDecl.getAs<Decl>());
- if (!RD->isAbstract()) {
- // Collect all the pure virtual methods and see if this is an abstract
- // class after all.
- PureVirtualMethodCollector Collector(Context, RD);
- if (!Collector.empty())
- RD->setAbstract(true);
- }
-
- if (RD->isAbstract())
- (void)AbstractClassUsageDiagnoser(*this, RD);
-
- if (!RD->isDependentType() && !RD->isInvalidDecl())
- AddImplicitlyDeclaredMembersToClass(RD);
+ CheckCompletedCXXClass(
+ dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -1974,7 +2035,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0),
- /*DInfo=*/0,
+ /*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
@@ -2046,7 +2107,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0),
- /*DInfo=*/0,
+ /*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
@@ -2058,7 +2119,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, /*DInfo=*/0,
+ ArgType, /*TInfo=*/0,
VarDecl::None, 0);
CopyConstructor->setParams(Context, &FromParam, 1);
ClassDecl->addDecl(CopyConstructor);
@@ -2132,7 +2193,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0),
- /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
+ /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -2142,13 +2203,14 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
- ArgType, /*DInfo=*/0,
+ ArgType, /*TInfo=*/0,
VarDecl::None, 0);
CopyAssignment->setParams(Context, &FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
ClassDecl->addDecl(CopyAssignment);
+ AddOverriddenMethods(ClassDecl, CopyAssignment);
}
if (!ClassDecl->hasUserDeclaredDestructor()) {
@@ -2814,6 +2876,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS,
+ bool HasUsingKeyword,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
@@ -2830,6 +2893,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
break;
case UnqualifiedId::IK_ConstructorName:
+ // C++0x inherited constructors.
+ if (getLangOptions().CPlusPlus0x) break;
+
Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor)
<< SS.getRange();
return DeclPtrTy();
@@ -2846,45 +2912,237 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
}
DeclarationName TargetName = GetNameFromUnqualifiedId(Name);
+ if (!TargetName)
+ return DeclPtrTy();
+
+ // Warn about using declarations.
+ // TODO: store that the declaration was written without 'using' and
+ // talk about access decls instead of using decls in the
+ // diagnostics.
+ if (!HasUsingKeyword) {
+ UsingLoc = Name.getSourceRange().getBegin();
+
+ Diag(UsingLoc, diag::warn_access_decl_deprecated)
+ << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(),
+ "using ");
+ }
+
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
Name.getSourceRange().getBegin(),
TargetName, AttrList,
/* IsInstantiation */ false,
IsTypeName, TypenameLoc);
- if (UD) {
- PushOnScopeChains(UD, S);
- UD->setAccess(AS);
- }
+ if (UD)
+ PushOnScopeChains(UD, S, /*AddToContext*/ false);
return DeclPtrTy::make(UD);
}
+/// Determines whether to create a using shadow decl for a particular
+/// decl, given the set of decls existing prior to this using lookup.
+bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
+ const LookupResult &Previous) {
+ // Diagnose finding a decl which is not from a base class of the
+ // current class. We do this now because there are cases where this
+ // function will silently decide not to build a shadow decl, which
+ // will pre-empt further diagnostics.
+ //
+ // We don't need to do this in C++0x because we do the check once on
+ // the qualifier.
+ //
+ // FIXME: diagnose the following if we care enough:
+ // struct A { int foo; };
+ // struct B : A { using A::foo; };
+ // template <class T> struct C : A {};
+ // template <class T> struct D : C<T> { using B::foo; } // <---
+ // This is invalid (during instantiation) in C++03 because B::foo
+ // resolves to the using decl in B, which is not a base class of D<T>.
+ // We can't diagnose it immediately because C<T> is an unknown
+ // specialization. The UsingShadowDecl in D<T> then points directly
+ // to A::foo, which will look well-formed when we instantiate.
+ // The right solution is to not collapse the shadow-decl chain.
+ if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) {
+ DeclContext *OrigDC = Orig->getDeclContext();
+
+ // Handle enums and anonymous structs.
+ if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent();
+ CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC);
+ while (OrigRec->isAnonymousStructOrUnion())
+ OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext());
+
+ if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) {
+ if (OrigDC == CurContext) {
+ Diag(Using->getLocation(),
+ diag::err_using_decl_nested_name_specifier_is_current_class)
+ << Using->getNestedNameRange();
+ Diag(Orig->getLocation(), diag::note_using_decl_target);
+ return true;
+ }
+
+ Diag(Using->getNestedNameRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << Using->getTargetNestedNameDecl()
+ << cast<CXXRecordDecl>(CurContext)
+ << Using->getNestedNameRange();
+ Diag(Orig->getLocation(), diag::note_using_decl_target);
+ return true;
+ }
+ }
+
+ if (Previous.empty()) return false;
+
+ NamedDecl *Target = Orig;
+ if (isa<UsingShadowDecl>(Target))
+ Target = cast<UsingShadowDecl>(Target)->getTargetDecl();
+
+ // If the target happens to be one of the previous declarations, we
+ // don't have a conflict.
+ //
+ // FIXME: but we might be increasing its access, in which case we
+ // should redeclare it.
+ NamedDecl *NonTag = 0, *Tag = 0;
+ for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+ I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+ if (D->getCanonicalDecl() == Target->getCanonicalDecl())
+ return false;
+
+ (isa<TagDecl>(D) ? Tag : NonTag) = D;
+ }
+
+ if (Target->isFunctionOrFunctionTemplate()) {
+ FunctionDecl *FD;
+ if (isa<FunctionTemplateDecl>(Target))
+ FD = cast<FunctionTemplateDecl>(Target)->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(Target);
+
+ NamedDecl *OldDecl = 0;
+ switch (CheckOverload(FD, Previous, OldDecl)) {
+ case Ovl_Overload:
+ return false;
+
+ case Ovl_NonFunction:
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ break;
+
+ // We found a decl with the exact signature.
+ case Ovl_Match:
+ if (isa<UsingShadowDecl>(OldDecl)) {
+ // Silently ignore the possible conflict.
+ return false;
+ }
+
+ // If we're in a record, we want to hide the target, so we
+ // return true (without a diagnostic) to tell the caller not to
+ // build a shadow decl.
+ if (CurContext->isRecord())
+ return true;
+
+ // If we're not in a record, this is an error.
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ break;
+ }
+
+ Diag(Target->getLocation(), diag::note_using_decl_target);
+ Diag(OldDecl->getLocation(), diag::note_using_decl_conflict);
+ return true;
+ }
+
+ // Target is not a function.
+
+ if (isa<TagDecl>(Target)) {
+ // No conflict between a tag and a non-tag.
+ if (!Tag) return false;
+
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ Diag(Target->getLocation(), diag::note_using_decl_target);
+ Diag(Tag->getLocation(), diag::note_using_decl_conflict);
+ return true;
+ }
+
+ // No conflict between a tag and a non-tag.
+ if (!NonTag) return false;
+
+ Diag(Using->getLocation(), diag::err_using_decl_conflict);
+ Diag(Target->getLocation(), diag::note_using_decl_target);
+ Diag(NonTag->getLocation(), diag::note_using_decl_conflict);
+ return true;
+}
+
/// Builds a shadow declaration corresponding to a 'using' declaration.
-static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S,
- AccessSpecifier AS,
- UsingDecl *UD, NamedDecl *Orig) {
- // FIXME: diagnose hiding, collisions
+UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
+ UsingDecl *UD,
+ NamedDecl *Orig) {
// If we resolved to another shadow declaration, just coalesce them.
- if (isa<UsingShadowDecl>(Orig)) {
- Orig = cast<UsingShadowDecl>(Orig)->getTargetDecl();
- assert(!isa<UsingShadowDecl>(Orig) && "nested shadow declaration");
+ NamedDecl *Target = Orig;
+ if (isa<UsingShadowDecl>(Target)) {
+ Target = cast<UsingShadowDecl>(Target)->getTargetDecl();
+ assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration");
}
UsingShadowDecl *Shadow
- = UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext,
- UD->getLocation(), UD, Orig);
+ = UsingShadowDecl::Create(Context, CurContext,
+ UD->getLocation(), UD, Target);
UD->addShadowDecl(Shadow);
if (S)
- SemaRef.PushOnScopeChains(Shadow, S);
+ PushOnScopeChains(Shadow, S);
else
- SemaRef.CurContext->addDecl(Shadow);
- Shadow->setAccess(AS);
+ CurContext->addDecl(Shadow);
+ Shadow->setAccess(UD->getAccess());
+
+ if (Orig->isInvalidDecl() || UD->isInvalidDecl())
+ Shadow->setInvalidDecl();
return Shadow;
}
+/// Hides a using shadow declaration. This is required by the current
+/// using-decl implementation when a resolvable using declaration in a
+/// class is followed by a declaration which would hide or override
+/// one or more of the using decl's targets; for example:
+///
+/// struct Base { void foo(int); };
+/// struct Derived : Base {
+/// using Base::foo;
+/// void foo(int);
+/// };
+///
+/// The governing language is C++03 [namespace.udecl]p12:
+///
+/// When a using-declaration brings names from a base class into a
+/// derived class scope, member functions in the derived class
+/// override and/or hide member functions with the same name and
+/// parameter types in a base class (rather than conflicting).
+///
+/// There are two ways to implement this:
+/// (1) optimistically create shadow decls when they're not hidden
+/// by existing declarations, or
+/// (2) don't create any shadow decls (or at least don't make them
+/// visible) until we've fully parsed/instantiated the class.
+/// The problem with (1) is that we might have to retroactively remove
+/// a shadow decl, which requires several O(n) operations because the
+/// decl structures are (very reasonably) not designed for removal.
+/// (2) avoids this but is very fiddly and phase-dependent.
+void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
+ // Remove it from the DeclContext...
+ Shadow->getDeclContext()->removeDecl(Shadow);
+
+ // ...and the scope, if applicable...
+ if (S) {
+ S->RemoveDecl(DeclPtrTy::make(static_cast<Decl*>(Shadow)));
+ IdResolver.RemoveDecl(Shadow);
+ }
+
+ // ...and the using decl.
+ Shadow->getUsingDecl()->removeShadowDecl(Shadow);
+
+ // TODO: complain somehow if Shadow was used. It shouldn't
+ // be possible for this to happen, because
+}
+
/// Builds a using declaration.
///
/// \param IsInstantiation - Whether this call arises from an
@@ -2910,56 +3168,76 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return 0;
}
+ // Do the redeclaration lookup in the current scope.
+ LookupResult Previous(*this, Name, IdentLoc, LookupUsingDeclName,
+ ForRedeclaration);
+ Previous.setHideTags(false);
+ if (S) {
+ LookupName(Previous, S);
+
+ // It is really dumb that we have to do this.
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (!isDeclInScope(D, CurContext, S))
+ F.erase();
+ }
+ F.done();
+ } else {
+ assert(IsInstantiation && "no scope in non-instantiation");
+ assert(CurContext->isRecord() && "scope not record in instantiation");
+ LookupQualifiedName(Previous, CurContext);
+ }
+
NestedNameSpecifier *NNS =
static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ // Check for invalid redeclarations.
+ if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous))
+ return 0;
+
+ // Check for bad qualifiers.
+ if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc))
+ return 0;
+
DeclContext *LookupContext = computeDeclContext(SS);
+ NamedDecl *D;
if (!LookupContext) {
if (IsTypeName) {
- return UnresolvedUsingTypenameDecl::Create(Context, CurContext,
- UsingLoc, TypenameLoc,
- SS.getRange(), NNS,
- IdentLoc, Name);
- } else {
- return UnresolvedUsingValueDecl::Create(Context, CurContext,
- UsingLoc, SS.getRange(), NNS,
+ // FIXME: not all declaration name kinds are legal here
+ D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
+ UsingLoc, TypenameLoc,
+ SS.getRange(), NNS,
IdentLoc, Name);
+ } else {
+ D = UnresolvedUsingValueDecl::Create(Context, CurContext,
+ UsingLoc, SS.getRange(), NNS,
+ IdentLoc, Name);
}
+ } else {
+ D = UsingDecl::Create(Context, CurContext, IdentLoc,
+ SS.getRange(), UsingLoc, NNS, Name,
+ IsTypeName);
}
+ D->setAccess(AS);
+ CurContext->addDecl(D);
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
- // C++0x N2914 [namespace.udecl]p3:
- // A using-declaration used as a member-declaration shall refer to a member
- // of a base class of the class being defined, shall refer to a member of an
- // anonymous union that is a member of a base class of the class being
- // defined, or shall refer to an enumerator for an enumeration type that is
- // a member of a base class of the class being defined.
-
- CXXRecordDecl *LookupRD = dyn_cast<CXXRecordDecl>(LookupContext);
- if (!LookupRD || !RD->isDerivedFrom(LookupRD)) {
- Diag(SS.getRange().getBegin(),
- diag::err_using_decl_nested_name_specifier_is_not_a_base_class)
- << NNS << RD->getDeclName();
- return 0;
- }
- } else {
- // C++0x N2914 [namespace.udecl]p8:
- // A using-declaration for a class member shall be a member-declaration.
- if (isa<CXXRecordDecl>(LookupContext)) {
- Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member)
- << SS.getRange();
- return 0;
- }
+ if (!LookupContext) return D;
+ UsingDecl *UD = cast<UsingDecl>(D);
+
+ if (RequireCompleteDeclContext(SS)) {
+ UD->setInvalidDecl();
+ return UD;
}
- // Look up the target name. Unlike most lookups, we do not want to
- // hide tag declarations: tag names are visible through the using
- // declaration even if hidden by ordinary names.
+ // Look up the target name.
+
LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName);
- // We don't hide tags behind ordinary decls if we're in a
- // non-dependent context, but in a dependent context, this is
- // important for the stability of two-phase lookup.
+ // Unlike most lookups, we don't always want to hide tag
+ // declarations: tag names are visible through the using declaration
+ // even if hidden by ordinary names, *except* in a dependent context
+ // where it's important for the sanity of two-phase lookup.
if (!IsInstantiation)
R.setHideTags(false);
@@ -2968,54 +3246,243 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (R.empty()) {
Diag(IdentLoc, diag::err_no_member)
<< Name << LookupContext << SS.getRange();
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
- if (R.isAmbiguous())
- return 0;
+ if (R.isAmbiguous()) {
+ UD->setInvalidDecl();
+ return UD;
+ }
if (IsTypeName) {
// If we asked for a typename and got a non-type decl, error out.
- if (R.getResultKind() != LookupResult::Found
- || !isa<TypeDecl>(R.getFoundDecl())) {
+ if (!R.getAsSingle<TypeDecl>()) {
Diag(IdentLoc, diag::err_using_typename_non_type);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
Diag((*I)->getUnderlyingDecl()->getLocation(),
diag::note_using_decl_target);
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
} else {
// If we asked for a non-typename and we got a type, error out,
// but only if this is an instantiation of an unresolved using
// decl. Otherwise just silently find the type name.
- if (IsInstantiation &&
- R.getResultKind() == LookupResult::Found &&
- isa<TypeDecl>(R.getFoundDecl())) {
+ if (IsInstantiation && R.getAsSingle<TypeDecl>()) {
Diag(IdentLoc, diag::err_using_dependent_value_is_type);
Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target);
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
}
// C++0x N2914 [namespace.udecl]p6:
// A using-declaration shall not name a namespace.
- if (R.getResultKind() == LookupResult::Found
- && isa<NamespaceDecl>(R.getFoundDecl())) {
+ if (R.getAsSingle<NamespaceDecl>()) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
<< SS.getRange();
- return 0;
+ UD->setInvalidDecl();
+ return UD;
}
- UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc,
- SS.getRange(), UsingLoc, NNS, Name,
- IsTypeName);
-
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- BuildUsingShadowDecl(*this, S, AS, UD, *I);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ if (!CheckUsingShadowDecl(UD, *I, Previous))
+ BuildUsingShadowDecl(S, UD, *I);
+ }
return UD;
}
+/// Checks that the given using declaration is not an invalid
+/// redeclaration. Note that this is checking only for the using decl
+/// itself, not for any ill-formedness among the UsingShadowDecls.
+bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
+ bool isTypeName,
+ const CXXScopeSpec &SS,
+ SourceLocation NameLoc,
+ const LookupResult &Prev) {
+ // C++03 [namespace.udecl]p8:
+ // C++0x [namespace.udecl]p10:
+ // A using-declaration is a declaration and can therefore be used
+ // repeatedly where (and only where) multiple declarations are
+ // allowed.
+ // That's only in file contexts.
+ if (CurContext->getLookupContext()->isFileContext())
+ return false;
+
+ NestedNameSpecifier *Qual
+ = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ bool DTypename;
+ NestedNameSpecifier *DQual;
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
+ DTypename = UD->isTypeName();
+ DQual = UD->getTargetNestedNameDecl();
+ } else if (UnresolvedUsingValueDecl *UD
+ = dyn_cast<UnresolvedUsingValueDecl>(D)) {
+ DTypename = false;
+ DQual = UD->getTargetNestedNameSpecifier();
+ } else if (UnresolvedUsingTypenameDecl *UD
+ = dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
+ DTypename = true;
+ DQual = UD->getTargetNestedNameSpecifier();
+ } else continue;
+
+ // using decls differ if one says 'typename' and the other doesn't.
+ // FIXME: non-dependent using decls?
+ if (isTypeName != DTypename) continue;
+
+ // using decls differ if they name different scopes (but note that
+ // template instantiation can cause this check to trigger when it
+ // didn't before instantiation).
+ if (Context.getCanonicalNestedNameSpecifier(Qual) !=
+ Context.getCanonicalNestedNameSpecifier(DQual))
+ continue;
+
+ Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange();
+ Diag(D->getLocation(), diag::note_using_decl) << 1;
+ return true;
+ }
+
+ return false;
+}
+
+
+/// Checks that the given nested-name qualifier used in a using decl
+/// in the current context is appropriately related to the current
+/// scope. If an error is found, diagnoses it and returns true.
+bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation NameLoc) {
+ DeclContext *NamedContext = computeDeclContext(SS);
+
+ if (!CurContext->isRecord()) {
+ // C++03 [namespace.udecl]p3:
+ // C++0x [namespace.udecl]p8:
+ // A using-declaration for a class member shall be a member-declaration.
+
+ // If we weren't able to compute a valid scope, it must be a
+ // dependent class scope.
+ if (!NamedContext || NamedContext->isRecord()) {
+ Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member)
+ << SS.getRange();
+ return true;
+ }
+
+ // Otherwise, everything is known to be fine.
+ return false;
+ }
+
+ // The current scope is a record.
+
+ // If the named context is dependent, we can't decide much.
+ if (!NamedContext) {
+ // FIXME: in C++0x, we can diagnose if we can prove that the
+ // nested-name-specifier does not refer to a base class, which is
+ // still possible in some cases.
+
+ // Otherwise we have to conservatively report that things might be
+ // okay.
+ return false;
+ }
+
+ if (!NamedContext->isRecord()) {
+ // Ideally this would point at the last name in the specifier,
+ // but we don't have that level of source info.
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_class)
+ << (NestedNameSpecifier*) SS.getScopeRep() << SS.getRange();
+ return true;
+ }
+
+ if (getLangOptions().CPlusPlus0x) {
+ // C++0x [namespace.udecl]p3:
+ // In a using-declaration used as a member-declaration, the
+ // nested-name-specifier shall name a base class of the class
+ // being defined.
+
+ if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(
+ cast<CXXRecordDecl>(NamedContext))) {
+ if (CurContext == NamedContext) {
+ Diag(NameLoc,
+ diag::err_using_decl_nested_name_specifier_is_current_class)
+ << SS.getRange();
+ return true;
+ }
+
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << (NestedNameSpecifier*) SS.getScopeRep()
+ << cast<CXXRecordDecl>(CurContext)
+ << SS.getRange();
+ return true;
+ }
+
+ return false;
+ }
+
+ // C++03 [namespace.udecl]p4:
+ // A using-declaration used as a member-declaration shall refer
+ // to a member of a base class of the class being defined [etc.].
+
+ // Salient point: SS doesn't have to name a base class as long as
+ // lookup only finds members from base classes. Therefore we can
+ // diagnose here only if we can prove that that can't happen,
+ // i.e. if the class hierarchies provably don't intersect.
+
+ // TODO: it would be nice if "definitely valid" results were cached
+ // in the UsingDecl and UsingShadowDecl so that these checks didn't
+ // need to be repeated.
+
+ struct UserData {
+ llvm::DenseSet<const CXXRecordDecl*> Bases;
+
+ static bool collect(const CXXRecordDecl *Base, void *OpaqueData) {
+ UserData *Data = reinterpret_cast<UserData*>(OpaqueData);
+ Data->Bases.insert(Base);
+ return true;
+ }
+
+ bool hasDependentBases(const CXXRecordDecl *Class) {
+ return !Class->forallBases(collect, this);
+ }
+
+ /// Returns true if the base is dependent or is one of the
+ /// accumulated base classes.
+ static bool doesNotContain(const CXXRecordDecl *Base, void *OpaqueData) {
+ UserData *Data = reinterpret_cast<UserData*>(OpaqueData);
+ return !Data->Bases.count(Base);
+ }
+
+ bool mightShareBases(const CXXRecordDecl *Class) {
+ return Bases.count(Class) || !Class->forallBases(doesNotContain, this);
+ }
+ };
+
+ UserData Data;
+
+ // Returns false if we find a dependent base.
+ if (Data.hasDependentBases(cast<CXXRecordDecl>(CurContext)))
+ return false;
+
+ // Returns false if the class has a dependent base or if it or one
+ // of its bases is present in the base set of the current context.
+ if (Data.mightShareBases(cast<CXXRecordDecl>(NamedContext)))
+ return false;
+
+ Diag(SS.getRange().getBegin(),
+ diag::err_using_decl_nested_name_specifier_is_not_base_class)
+ << (NestedNameSpecifier*) SS.getScopeRep()
+ << cast<CXXRecordDecl>(CurContext)
+ << SS.getRange();
+
+ return true;
+}
+
Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
@@ -3081,7 +3548,6 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
} else {
Constructor->setUsed();
}
- return;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3163,7 +3629,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *BaseAssignOpMethod =
- getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
+ getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
+ BaseClassDecl))
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -3175,7 +3642,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXMethodDecl *FieldAssignOpMethod =
- getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
+ getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
+ FieldClassDecl))
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
} else if (FieldType->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
@@ -3196,7 +3664,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
}
CXXMethodDecl *
-Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
+Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
+ ParmVarDecl *ParmDecl,
CXXRecordDecl *ClassDecl) {
QualType LHSType = Context.getTypeDeclType(ClassDecl);
QualType RHSType(LHSType);
@@ -3206,18 +3675,17 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
RHSType = Context.getCVRQualifiedType(RHSType,
ParmDecl->getType().getCVRQualifiers());
ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
- SourceLocation()));
+ LHSType,
+ SourceLocation()));
ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
- SourceLocation()));
+ RHSType,
+ CurrentLocation));
Expr *Args[2] = { &*LHS, &*RHS };
OverloadCandidateSet CandidateSet;
AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet,
- ClassDecl->getLocation(), Best) == OR_Success)
+ if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success)
return cast<CXXMethodDecl>(Best->Function);
assert(false &&
"getAssignOperatorMethod - copy assignment operator method not found");
@@ -3286,8 +3754,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
if (ICE->getCastKind() == CastExpr::CK_NoOp)
E = ICE->getSubExpr();
-
- if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E))
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ Elidable = !CE->getCallReturnType()->isReferenceType();
+ else if (isa<CXXTemporaryObjectExpr>(E))
Elidable = true;
}
@@ -3428,7 +3898,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
SourceRange(VDecl->getLocation(),
RParenLoc),
VDecl->getDeclName(),
- IK_Direct,
+ InitializationKind::CreateDirect(VDecl->getLocation(),
+ LParenLoc,
+ RParenLoc),
ConstructorArgs);
if (!Constructor)
RealDecl->setInvalidDecl();
@@ -3464,7 +3936,7 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
QualType ClassType,
Expr **Args,
unsigned NumArgs,
- Sema::InitializationKind Kind,
+ InitializationKind Kind,
OverloadCandidateSet &CandidateSet) {
// C++ [dcl.init]p14:
// If the initialization is direct-initialization, or if it is
@@ -3499,10 +3971,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
else
Constructor = cast<CXXConstructorDecl>(*Con);
- if ((Kind == Sema::IK_Direct) ||
- (Kind == Sema::IK_Copy &&
+ if ((Kind.getKind() == InitializationKind::IK_Direct) ||
+ (Kind.getKind() == InitializationKind::IK_Value) ||
+ (Kind.getKind() == InitializationKind::IK_Copy &&
Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
- (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) {
+ ((Kind.getKind() == InitializationKind::IK_Default) &&
+ Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl,
/*ExplicitArgs*/ 0,
@@ -3774,7 +4248,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// real, update the initializer with the resulting function.
if (!ICS) {
if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
+ return true;
Init = FixOverloadedFunctionReference(Init, Fn);
}
@@ -3874,23 +4348,28 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= T2RecordDecl->getVisibleConversionFunctions();
for (UnresolvedSet::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
FunctionTemplateDecl *ConvTemplate
- = dyn_cast<FunctionTemplateDecl>(*I);
+ = dyn_cast<FunctionTemplateDecl>(D);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*I);
+ Conv = cast<CXXConversionDecl>(D);
// If the conversion function doesn't return a reference type,
// it can't be considered for this conversion.
if (Conv->getConversionType()->isLValueReferenceType() &&
(AllowExplicit || !Conv->isExplicit())) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, Init, DeclType,
- CandidateSet);
+ AddTemplateConversionCandidate(ConvTemplate, ActingDC,
+ Init, DeclType, CandidateSet);
else
- AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet);
}
}
@@ -4125,6 +4604,138 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
}
}
+static inline bool
+CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
+ const FunctionDecl *FnDecl) {
+ const DeclContext *DC = FnDecl->getDeclContext()->getLookupContext();
+ if (isa<NamespaceDecl>(DC)) {
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_declared_in_namespace)
+ << FnDecl->getDeclName();
+ }
+
+ if (isa<TranslationUnitDecl>(DC) &&
+ FnDecl->getStorageClass() == FunctionDecl::Static) {
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_declared_static)
+ << FnDecl->getDeclName();
+ }
+
+ return false;
+}
+
+static inline bool
+CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
+ CanQualType ExpectedResultType,
+ CanQualType ExpectedFirstParamType,
+ unsigned DependentParamTypeDiag,
+ unsigned InvalidParamTypeDiag) {
+ QualType ResultType =
+ FnDecl->getType()->getAs<FunctionType>()->getResultType();
+
+ // Check that the result type is not dependent.
+ if (ResultType->isDependentType())
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_dependent_result_type)
+ << FnDecl->getDeclName() << ExpectedResultType;
+
+ // Check that the result type is what we expect.
+ if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_invalid_result_type)
+ << FnDecl->getDeclName() << ExpectedResultType;
+
+ // A function template must have at least 2 parameters.
+ if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_template_too_few_parameters)
+ << FnDecl->getDeclName();
+
+ // The function decl must have at least 1 parameter.
+ if (FnDecl->getNumParams() == 0)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_too_few_parameters)
+ << FnDecl->getDeclName();
+
+ // Check the the first parameter type is not dependent.
+ QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
+ if (FirstParamType->isDependentType())
+ return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag)
+ << FnDecl->getDeclName() << ExpectedFirstParamType;
+
+ // Check that the first parameter type is what we expect.
+ if (SemaRef.Context.getCanonicalType(FirstParamType) !=
+ ExpectedFirstParamType)
+ return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
+ << FnDecl->getDeclName() << ExpectedFirstParamType;
+
+ return false;
+}
+
+static bool
+CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+ // C++ [basic.stc.dynamic.allocation]p1:
+ // A program is ill-formed if an allocation function is declared in a
+ // namespace scope other than global scope or declared static in global
+ // scope.
+ if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
+ return true;
+
+ CanQualType SizeTy =
+ SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType());
+
+ // C++ [basic.stc.dynamic.allocation]p1:
+ // The return type shall be void*. The first parameter shall have type
+ // std::size_t.
+ if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy,
+ SizeTy,
+ diag::err_operator_new_dependent_param_type,
+ diag::err_operator_new_param_type))
+ return true;
+
+ // C++ [basic.stc.dynamic.allocation]p1:
+ // The first parameter shall not have an associated default argument.
+ if (FnDecl->getParamDecl(0)->hasDefaultArg())
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_default_arg)
+ << FnDecl->getDeclName() << FnDecl->getParamDecl(0)->getDefaultArgRange();
+
+ return false;
+}
+
+static bool
+CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+ // C++ [basic.stc.dynamic.deallocation]p1:
+ // A program is ill-formed if deallocation functions are declared in a
+ // namespace scope other than global scope or declared static in global
+ // scope.
+ if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
+ return true;
+
+ // C++ [basic.stc.dynamic.deallocation]p2:
+ // Each deallocation function shall return void and its first parameter
+ // shall be void*.
+ if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy,
+ SemaRef.Context.VoidPtrTy,
+ diag::err_operator_delete_dependent_param_type,
+ diag::err_operator_delete_param_type))
+ return true;
+
+ QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
+ if (FirstParamType->isDependentType())
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_delete_dependent_param_type)
+ << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy;
+
+ if (SemaRef.Context.getCanonicalType(FirstParamType) !=
+ SemaRef.Context.VoidPtrTy)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_delete_param_type)
+ << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy;
+
+ return false;
+}
+
/// CheckOverloadedOperatorDeclaration - Check whether the declaration
/// of this overloaded operator is well-formed. If so, returns false;
/// otherwise, emits appropriate diagnostics and returns true.
@@ -4140,29 +4751,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// described completely in 3.7.3. The attributes and restrictions
// found in the rest of this subclause do not apply to them unless
// explicitly stated in 3.7.3.
- // FIXME: Write a separate routine for checking this. For now, just allow it.
if (Op == OO_Delete || Op == OO_Array_Delete)
- return false;
+ return CheckOperatorDeleteDeclaration(*this, FnDecl);
- if (Op == OO_New || Op == OO_Array_New) {
- bool ret = false;
- if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
- QualType SizeTy = Context.getCanonicalType(Context.getSizeType());
- QualType T = Context.getCanonicalType((*Param)->getType());
- if (!T->isDependentType() && SizeTy != T) {
- Diag(FnDecl->getLocation(),
- diag::err_operator_new_param_type) << FnDecl->getDeclName()
- << SizeTy;
- ret = true;
- }
- }
- QualType ResultTy = Context.getCanonicalType(FnDecl->getResultType());
- if (!ResultTy->isDependentType() && ResultTy != Context.VoidPtrTy)
- return Diag(FnDecl->getLocation(),
- diag::err_operator_new_result_type) << FnDecl->getDeclName()
- << static_cast<QualType>(Context.VoidPtrTy);
- return ret;
- }
+ if (Op == OO_New || Op == OO_Array_New)
+ return CheckOperatorNewDeclaration(*this, FnDecl);
// C++ [over.oper]p6:
// An operator function shall either be a non-static member
@@ -4201,14 +4794,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
if (Op != OO_Call) {
for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
Param != FnDecl->param_end(); ++Param) {
- if ((*Param)->hasUnparsedDefaultArg())
+ if ((*Param)->hasDefaultArg())
return Diag((*Param)->getLocation(),
diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName();
- else if (Expr *DefArg = (*Param)->getDefaultArg())
- return Diag((*Param)->getLocation(),
- diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName() << DefArg->getSourceRange();
+ << FnDecl->getDeclName() << (*Param)->getDefaultArgRange();
}
}
@@ -4346,7 +4935,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S,
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
- DeclaratorInfo *DInfo,
+ TypeSourceInfo *TInfo,
IdentifierInfo *Name,
SourceLocation Loc,
SourceRange Range) {
@@ -4396,7 +4985,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
// FIXME: Need to check for abstract classes.
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, DInfo, VarDecl::None);
+ Name, ExDeclType, TInfo, VarDecl::None);
if (Invalid)
ExDecl->setInvalidDecl();
@@ -4407,8 +4996,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
/// handler.
Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
- DeclaratorInfo *DInfo = 0;
- QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType ExDeclType = GetTypeForDeclarator(D, S, &TInfo);
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
@@ -4428,7 +5017,7 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Invalid = true;
}
- VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo,
+ VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, TInfo,
D.getIdentifier(),
D.getIdentifierLoc(),
D.getDeclSpec().getSourceRange());
@@ -4462,10 +5051,8 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
}
if (Value == 0) {
- std::string str(AssertMessage->getStrData(),
- AssertMessage->getByteLength());
Diag(AssertLoc, diag::err_static_assert_failed)
- << str << AssertExpr->getSourceRange();
+ << AssertMessage->getString() << AssertExpr->getSourceRange();
}
}
@@ -4602,8 +5189,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
SourceLocation Loc = D.getIdentifierLoc();
- DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(D, S, &DInfo);
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeForDeclarator(D, S, &TInfo);
// C++ [class.friend]p1
// A friend of a class is a function or class....
@@ -4726,7 +5313,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
}
bool Redeclaration = false;
- NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, Previous,
+ NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, TInfo, Previous,
move(TemplateParams),
IsDefinition,
Redeclaration);
@@ -4890,6 +5477,26 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
return false;
}
+/// \brief Mark the given method pure.
+///
+/// \param Method the method to be marked pure.
+///
+/// \param InitRange the source range that covers the "0" initializer.
+bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
+ if (Method->isVirtual() || Method->getParent()->isDependentContext()) {
+ Method->setPure();
+
+ // A class is abstract if at least one function is pure virtual.
+ Method->getParent()->setAbstract(true);
+ return false;
+ }
+
+ if (!Method->isInvalidDecl())
+ Diag(Method->getLocation(), diag::err_non_virtual_pure)
+ << Method->getDeclName() << InitRange;
+ return true;
+}
+
/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
/// initializer for the declaration 'Dcl'.
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
@@ -4949,9 +5556,9 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
- DeclaratorInfo *DInfo = 0;
+ TypeSourceInfo *TInfo = 0;
TagDecl *OwnedTag = 0;
- QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag);
+ QualType Ty = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag);
if (Ty->isFunctionType()) { // The declarator shall not specify a function...
// We exit without creating a CXXConditionDeclExpr because a FunctionDecl
@@ -4972,3 +5579,80 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
VD->setDeclaredInCondition(true);
return Dcl;
}
+
+void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
+ CXXMethodDecl *MD) {
+ // Ignore dependent types.
+ if (MD->isDependentContext())
+ return;
+
+ CXXRecordDecl *RD = MD->getParent();
+
+ // Ignore classes without a vtable.
+ if (!RD->isDynamicClass())
+ return;
+
+ if (!MD->isOutOfLine()) {
+ // The only inline functions we care about are constructors. We also defer
+ // marking the virtual members as referenced until we've reached the end
+ // of the translation unit. We do this because we need to know the key
+ // function of the class in order to determine the key function.
+ if (isa<CXXConstructorDecl>(MD))
+ ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc));
+ return;
+ }
+
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+
+ if (!KeyFunction) {
+ // This record does not have a key function, so we assume that the vtable
+ // will be emitted when it's used by the constructor.
+ if (!isa<CXXConstructorDecl>(MD))
+ return;
+ } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
+ // We don't have the right key function.
+ return;
+ }
+
+ // Mark the members as referenced.
+ MarkVirtualMembersReferenced(Loc, RD);
+ ClassesWithUnmarkedVirtualMembers.erase(RD);
+}
+
+bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
+ if (ClassesWithUnmarkedVirtualMembers.empty())
+ return false;
+
+ for (std::map<CXXRecordDecl *, SourceLocation>::iterator i =
+ ClassesWithUnmarkedVirtualMembers.begin(),
+ e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) {
+ CXXRecordDecl *RD = i->first;
+
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+ if (KeyFunction) {
+ // We know that the class has a key function. If the key function was
+ // declared in this translation unit, then it the class decl would not
+ // have been in the ClassesWithUnmarkedVirtualMembers map.
+ continue;
+ }
+
+ SourceLocation Loc = i->second;
+ MarkVirtualMembersReferenced(Loc, RD);
+ }
+
+ ClassesWithUnmarkedVirtualMembers.clear();
+ return true;
+}
+
+void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ CXXMethodDecl *MD = *i;
+
+ // C++ [basic.def.odr]p2:
+ // [...] A virtual member function is used if it is not pure. [...]
+ if (MD->isVirtual() && !MD->isPure())
+ MarkDeclarationReferenced(Loc, MD);
+ }
+}
+