aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2088
1 files changed, 1111 insertions, 977 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 39e3739878f9..6259b85af480 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -16,12 +16,13 @@
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Template.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -297,13 +298,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
<< OldParam->getDefaultArgRange();
Invalid = true;
} else if (OldParam->hasDefaultArg()) {
- // Merge the old default argument into the new parameter
+ // Merge the old default argument into the new parameter.
+ // It's important to use getInit() here; getDefaultArg()
+ // strips off any top-level CXXExprWithTemporaries.
NewParam->setHasInheritedDefaultArg();
if (OldParam->hasUninstantiatedDefaultArg())
NewParam->setUninstantiatedDefaultArg(
OldParam->getUninstantiatedDefaultArg());
else
- NewParam->setDefaultArg(OldParam->getDefaultArg());
+ NewParam->setDefaultArg(OldParam->getInit());
} else if (NewParam->hasDefaultArg()) {
if (New->getDescribedFunctionTemplate()) {
// Paragraph 4, quoted above, only applies to non-template functions.
@@ -710,6 +713,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
return DerivedRD->isDerivedFrom(BaseRD, Paths);
}
+void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXBaseSpecifierArray &BasePathArray) {
+ assert(BasePathArray.empty() && "Base path array must be empty!");
+ assert(Paths.isRecordingPaths() && "Must record paths!");
+
+ const CXXBasePath &Path = Paths.front();
+
+ // We first go backward and check if we have a virtual base.
+ // FIXME: It would be better if CXXBasePath had the base specifier for
+ // the nearest virtual base.
+ unsigned Start = 0;
+ for (unsigned I = Path.size(); I != 0; --I) {
+ if (Path[I - 1].Base->isVirtual()) {
+ Start = I - 1;
+ break;
+ }
+ }
+
+ // Now add all bases.
+ for (unsigned I = Start, E = Path.size(); I != E; ++I)
+ BasePathArray.push_back(Path[I].Base);
+}
+
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -723,7 +749,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
- DeclarationName Name) {
+ DeclarationName Name,
+ CXXBaseSpecifierArray *BasePath) {
// First, determine whether the path from Derived to Base is
// ambiguous. This is slightly more expensive than checking whether
// the Derived to Base conversion exists, because here we need to
@@ -736,17 +763,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (!InaccessibleBaseID)
- return false;
-
- // Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
- InaccessibleBaseID)) {
- case AR_accessible: return false;
- case AR_inaccessible: return true;
- case AR_dependent: return false;
- case AR_delayed: return false;
+ if (InaccessibleBaseID) {
+ // Check that the base class can be accessed.
+ switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
+ InaccessibleBaseID)) {
+ case AR_inaccessible:
+ return true;
+ case AR_accessible:
+ case AR_dependent:
+ case AR_delayed:
+ break;
+ }
}
+
+ // Build a base path if necessary.
+ if (BasePath)
+ BuildBasePathArray(Paths, *BasePath);
+ return false;
}
// We know that the derived-to-base conversion is ambiguous, and
@@ -775,12 +808,14 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
+ CXXBaseSpecifierArray *BasePath,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
IgnoreAccess ? 0
: diag::err_upcast_to_inaccessible_base,
diag::err_ambiguous_derived_to_base_conv,
- Loc, Range, DeclarationName());
+ Loc, Range, DeclarationName(),
+ BasePath);
}
@@ -1013,7 +1048,7 @@ static bool FindBaseInitializer(Sema &SemaRef,
Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
@@ -1076,6 +1111,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!TyD) {
if (R.isAmbiguous()) return true;
+ // We don't want access-control diagnostics here.
+ R.suppressDiagnostics();
+
if (SS.isSet() && isDependentScopeSpecifier(SS)) {
bool NotUnknownSpecialization = false;
DeclContext *DC = computeDeclContext(SS, false);
@@ -1085,7 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!NotUnknownSpecialization) {
// When the scope specifier can refer to a member of an unknown
// specialization, we take it as a type name.
- BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ BaseType = CheckTypenameType(ETK_None,
+ (NestedNameSpecifier *)SS.getScopeRep(),
*MemberOrBase, SS.getRange());
if (BaseType.isNull())
return true;
@@ -1096,7 +1135,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// If no results were found, try to correct typos.
if (R.empty() && BaseType.isNull() &&
- CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
+ CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) &&
+ R.isSingleResult()) {
if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
// We have found a non-static data member with a similar
@@ -1236,7 +1276,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
if (FieldType->isDependentType() || HasDependentArg) {
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
@@ -1334,6 +1373,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
ExprTemporaries.end());
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false,
LParenLoc,
BaseInit.takeAs<Expr>(),
RParenLoc);
@@ -1369,7 +1409,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// mem-initializer is ill-formed.
if (!DirectBaseSpec && !VirtualBaseSpec)
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
+ << BaseType << Context.getTypeDeclType(ClassDecl)
<< BaseTInfo->getTypeLoc().getSourceRange();
CXXBaseSpecifier *BaseSpec
@@ -1379,7 +1419,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// Initialize the base.
InitializedEntity BaseEntity =
- InitializedEntity::InitializeBase(Context, BaseSpec);
+ InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec);
InitializationKind Kind =
InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
@@ -1414,23 +1454,199 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
RParenLoc));
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ BaseSpec->isVirtual(),
LParenLoc,
Init.takeAs<Expr>(),
RParenLoc);
}
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ BaseSpec->isVirtual(),
LParenLoc,
BaseInit.takeAs<Expr>(),
RParenLoc);
}
+/// ImplicitInitializerKind - How an implicit base or member initializer should
+/// initialize its base or member.
+enum ImplicitInitializerKind {
+ IIK_Default,
+ IIK_Copy,
+ IIK_Move
+};
+
+static bool
+BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
+ ImplicitInitializerKind ImplicitInitKind,
+ CXXBaseSpecifier *BaseSpec,
+ bool IsInheritedVirtualBase,
+ CXXBaseOrMemberInitializer *&CXXBaseInit) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec,
+ IsInheritedVirtualBase);
+
+ Sema::OwningExprResult BaseInit(SemaRef);
+
+ switch (ImplicitInitKind) {
+ case IIK_Default: {
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ break;
+ }
+
+ case IIK_Copy: {
+ ParmVarDecl *Param = Constructor->getParamDecl(0);
+ QualType ParamType = Param->getType().getNonReferenceType();
+
+ Expr *CopyCtorArg =
+ DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ Constructor->getLocation(), ParamType, 0);
+
+ // Cast to the base class to avoid ambiguities.
+ QualType ArgTy =
+ SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
+ ParamType.getQualifiers());
+ SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
+ CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/true,
+ CXXBaseSpecifierArray(BaseSpec));
+
+ InitializationKind InitKind
+ = InitializationKind::CreateDirect(Constructor->getLocation(),
+ SourceLocation(), SourceLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ &CopyCtorArg, 1);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef,
+ (void**)&CopyCtorArg, 1));
+ break;
+ }
+
+ case IIK_Move:
+ assert(false && "Unhandled initializer kind!");
+ }
+
+ BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid())
+ return true;
+
+ CXXBaseInit =
+ new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context,
+ SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
+ SourceLocation()),
+ BaseSpec->isVirtual(),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+
+ return false;
+}
+
+static bool
+BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
+ ImplicitInitializerKind ImplicitInitKind,
+ FieldDecl *Field,
+ CXXBaseOrMemberInitializer *&CXXMemberInit) {
+ if (ImplicitInitKind == IIK_Copy) {
+ // FIXME: We should not return early here, but will do so until
+ // we know how to handle copy initialization of arrays.
+ CXXMemberInit = 0;
+ return false;
+
+ ParmVarDecl *Param = Constructor->getParamDecl(0);
+ QualType ParamType = Param->getType().getNonReferenceType();
+
+ Expr *MemberExprBase =
+ DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ SourceLocation(), ParamType, 0);
+
+
+ Expr *CopyCtorArg =
+ MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false,
+ 0, SourceRange(), Field,
+ DeclAccessPair::make(Field, Field->getAccess()),
+ SourceLocation(), 0,
+ Field->getType().getNonReferenceType());
+
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDirect(Constructor->getLocation(),
+ SourceLocation(), SourceLocation());
+
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ &CopyCtorArg, 1);
+
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+ if (MemberInit.isInvalid())
+ return true;
+
+ CXXMemberInit = 0;
+ return false;
+ }
+
+ assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
+
+ QualType FieldBaseElementType =
+ SemaRef.Context.getBaseElementType(Field->getType());
+
+ if (FieldBaseElementType->isRecordType()) {
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDefault(Constructor->getLocation());
+
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid())
+ return true;
+
+ CXXMemberInit =
+ new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context,
+ Field, SourceLocation(),
+ SourceLocation(),
+ MemberInit.takeAs<Expr>(),
+ SourceLocation());
+ return false;
+ }
+
+ if (FieldBaseElementType->isReferenceType()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 0 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ if (FieldBaseElementType.isConstQualified()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 1 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ // Nothing to initialize.
+ CXXMemberInit = 0;
+ return false;
+}
+
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
bool AnyErrors) {
- if (Constructor->isDependentContext()) {
+ if (Constructor->getDeclContext()->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
if (NumInitializers > 0) {
@@ -1445,6 +1661,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
return false;
}
+ ImplicitInitializerKind ImplicitInitKind = IIK_Default;
+
+ // FIXME: Handle implicit move constructors.
+ if (Constructor->isImplicit() && Constructor->isCopyConstructor())
+ ImplicitInitKind = IIK_Copy;
+
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
@@ -1464,7 +1686,13 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
AllBaseFields[Member->getMember()] = Member;
}
- llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
+ // Keep track of the direct virtual bases.
+ llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases;
+ for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ DirectVBases.insert(I);
+ }
// Push virtual bases before others.
for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
@@ -1474,26 +1702,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
} else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, VBase);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
+ bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
+ CXXBaseOrMemberInitializer *CXXBaseInit;
+ if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ VBase, IsInheritedVirtualBase,
+ CXXBaseInit)) {
HadError = true;
continue;
}
-
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(VBase->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
+
AllToInit.push_back(CXXBaseInit);
}
}
@@ -1508,26 +1725,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
} else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, Base);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
+ CXXBaseOrMemberInitializer *CXXBaseInit;
+ if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ Base, /*IsInheritedVirtualBase=*/false,
+ CXXBaseInit)) {
HadError = true;
continue;
}
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(Base->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
AllToInit.push_back(CXXBaseInit);
}
}
@@ -1560,54 +1765,19 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
}
- if ((*Field)->getType()->isDependentType() || AnyErrors)
+ if (AnyErrors)
continue;
- QualType FT = Context.getBaseElementType((*Field)->getType());
- if (FT->getAs<RecordType>()) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeMember(*Field);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
-
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
- if (MemberInit.isInvalid()) {
- HadError = true;
- continue;
- }
-
- // Don't attach synthesized member initializers in a dependent
- // context; they'll be regenerated a template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
-
- CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(Context,
- *Field, SourceLocation(),
- SourceLocation(),
- MemberInit.takeAs<Expr>(),
- SourceLocation());
-
- AllToInit.push_back(Member);
- }
- else if (FT->isReferenceType()) {
- Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
- << 0 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- HadError = true;
- }
- else if (FT.isConstQualified()) {
- Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ CXXBaseOrMemberInitializer *Member;
+ if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind,
+ *Field, Member)) {
HadError = true;
+ continue;
}
+
+ // If the member doesn't need to be initialized, it will be null.
+ if (Member)
+ AllToInit.push_back(Member);
}
NumInitializers = AllToInit.size();
@@ -1657,11 +1827,20 @@ static void *GetKeyForMember(ASTContext &Context,
if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
Field = Member->getAnonUnionMember();
- // If the field is a member of an anonymous union, we use record decl of the
- // union as the key.
+ // If the field is a member of an anonymous struct or union, our key
+ // is the anonymous record decl that's a direct child of the class.
RecordDecl *RD = Field->getParent();
- if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+ if (RD->isAnonymousStructOrUnion()) {
+ while (true) {
+ RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext());
+ if (Parent->isAnonymousStructOrUnion())
+ RD = Parent;
+ else
+ break;
+ }
+
return static_cast<void *>(RD);
+ }
return static_cast<void *>(Field);
}
@@ -1669,89 +1848,153 @@ static void *GetKeyForMember(ASTContext &Context,
static void
DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
const CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **MemInits,
- unsigned NumMemInits) {
- if (Constructor->isDependentContext())
+ CXXBaseOrMemberInitializer **Inits,
+ unsigned NumInits) {
+ if (Constructor->getDeclContext()->isDependentContext())
return;
- if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
- Diagnostic::Ignored &&
- SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
- Diagnostic::Ignored)
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order)
+ == Diagnostic::Ignored)
return;
- // Also issue warning if order of ctor-initializer list does not match order
- // of 1) base class declarations and 2) order of non-static data members.
- llvm::SmallVector<const void*, 32> AllBaseOrMembers;
+ // Build the list of bases and members in the order that they'll
+ // actually be initialized. The explicit initializers should be in
+ // this same order but may be missing things.
+ llvm::SmallVector<const void*, 32> IdealInitKeys;
const CXXRecordDecl *ClassDecl = Constructor->getParent();
- // Push virtual bases before others.
+ // 1. Virtual bases.
for (CXXRecordDecl::base_class_const_iterator VBase =
ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- VBase->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType()));
+ // 2. Non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Virtuals are alread in the virtual base list and are constructed
- // first.
if (Base->isVirtual())
continue;
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- Base->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType()));
}
+ // 3. Direct fields.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field)
- AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field));
+ IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
- int Last = AllBaseOrMembers.size();
- int curIndex = 0;
- CXXBaseOrMemberInitializer *PrevMember = 0;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
- void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
+ unsigned NumIdealInits = IdealInitKeys.size();
+ unsigned IdealIndex = 0;
+
+ CXXBaseOrMemberInitializer *PrevInit = 0;
+ for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ CXXBaseOrMemberInitializer *Init = Inits[InitIndex];
+ void *InitKey = GetKeyForMember(SemaRef.Context, Init, true);
- for (; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ // Scan forward to try to find this initializer in the idealized
+ // initializers list.
+ for (; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
- if (curIndex == Last) {
- assert(PrevMember && "Member not in member list?!");
- // Initializer as specified in ctor-initializer list is out of order.
- // Issue a warning diagnostic.
- if (PrevMember->isBaseInitializer()) {
- // Diagnostics is for an initialized base class.
- Type *BaseClass = PrevMember->getBaseClass();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
- << QualType(BaseClass, 0);
- } else {
- FieldDecl *Field = PrevMember->getMember();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
- << Field->getNameAsString();
- }
- // Also the note!
- if (FieldDecl *Field = Member->getMember())
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
- << Field->getNameAsString();
- else {
- Type *BaseClass = Member->getBaseClass();
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 1
- << QualType(BaseClass, 0);
- }
- for (curIndex = 0; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+
+ // If we didn't find this initializer, it must be because we
+ // scanned past it on a previous iteration. That can only
+ // happen if we're out of order; emit a warning.
+ if (IdealIndex == NumIdealInits) {
+ assert(PrevInit && "initializer not found in initializer list");
+
+ Sema::SemaDiagnosticBuilder D =
+ SemaRef.Diag(PrevInit->getSourceLocation(),
+ diag::warn_initializer_out_of_order);
+
+ if (PrevInit->isMemberInitializer())
+ D << 0 << PrevInit->getMember()->getDeclName();
+ else
+ D << 1 << PrevInit->getBaseClassInfo()->getType();
+
+ if (Init->isMemberInitializer())
+ D << 0 << Init->getMember()->getDeclName();
+ else
+ D << 1 << Init->getBaseClassInfo()->getType();
+
+ // Move back to the initializer's location in the ideal list.
+ for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
+
+ assert(IdealIndex != NumIdealInits &&
+ "initializer not found in initializer list");
}
- PrevMember = Member;
+
+ PrevInit = Init;
}
}
+namespace {
+bool CheckRedundantInit(Sema &S,
+ CXXBaseOrMemberInitializer *Init,
+ CXXBaseOrMemberInitializer *&PrevInit) {
+ if (!PrevInit) {
+ PrevInit = Init;
+ return false;
+ }
+
+ if (FieldDecl *Field = Init->getMember())
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_mem_initialization)
+ << Field->getDeclName()
+ << Init->getSourceRange();
+ else {
+ Type *BaseClass = Init->getBaseClass();
+ assert(BaseClass && "neither field nor base");
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_base_initialization)
+ << QualType(BaseClass, 0)
+ << Init->getSourceRange();
+ }
+ S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer)
+ << 0 << PrevInit->getSourceRange();
+
+ return true;
+}
+
+typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry;
+typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap;
+
+bool CheckRedundantUnionInit(Sema &S,
+ CXXBaseOrMemberInitializer *Init,
+ RedundantUnionMap &Unions) {
+ FieldDecl *Field = Init->getMember();
+ RecordDecl *Parent = Field->getParent();
+ if (!Parent->isAnonymousStructOrUnion())
+ return false;
+
+ NamedDecl *Child = Field;
+ do {
+ if (Parent->isUnion()) {
+ UnionEntry &En = Unions[Parent];
+ if (En.first && En.first != Child) {
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_mem_union_initialization)
+ << Field->getDeclName()
+ << Init->getSourceRange();
+ S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
+ << 0 << En.second->getSourceRange();
+ return true;
+ } else if (!En.first) {
+ En.first = Child;
+ En.second = Init;
+ }
+ }
+
+ Child = Parent;
+ Parent = cast<RecordDecl>(Parent->getDeclContext());
+ } while (Parent->isAnonymousStructOrUnion());
+
+ return false;
+}
+}
+
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
@@ -1772,34 +2015,29 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
CXXBaseOrMemberInitializer **MemInits =
reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
-
+
+ // Mapping for the duplicate initializers check.
+ // For member initializers, this is keyed with a FieldDecl*.
+ // For base initializers, this is keyed with a Type*.
llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+
+ // Mapping for the inconsistent anonymous-union initializers check.
+ RedundantUnionMap MemberUnions;
+
bool HadError = false;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
+ CXXBaseOrMemberInitializer *Init = MemInits[i];
- void *KeyToMember = GetKeyForMember(Context, Member);
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
- }
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << 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)
- << Member->getSourceRange();
+ if (Init->isMemberInitializer()) {
+ FieldDecl *Field = Init->getMember();
+ if (CheckRedundantInit(*this, Init, Members[Field]) ||
+ CheckRedundantUnionInit(*this, Init, MemberUnions))
+ HadError = true;
+ } else {
+ void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+ if (CheckRedundantInit(*this, Init, Members[Key]))
+ HadError = true;
}
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- HadError = true;
}
if (HadError)
@@ -2060,12 +2298,12 @@ 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) {
+void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
if (!Record || Record->isInvalidDecl())
return;
if (!Record->isDependentType())
- AddImplicitlyDeclaredMembersToClass(Record);
+ AddImplicitlyDeclaredMembersToClass(S, Record);
if (Record->isInvalidDecl())
return;
@@ -2141,6 +2379,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
+
+ // If this is not an aggregate type and has no user-declared constructor,
+ // complain about any non-static data members of reference or const scalar
+ // type, since they will never get initializers.
+ if (!Record->isInvalidDecl() && !Record->isDependentType() &&
+ !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) {
+ bool Complained = false;
+ for (RecordDecl::field_iterator F = Record->field_begin(),
+ FEnd = Record->field_end();
+ F != FEnd; ++F) {
+ if (F->getType()->isReferenceType() ||
+ (F->getType().isConstQualified() && F->getType()->isScalarType())) {
+ if (!Complained) {
+ Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst)
+ << Record->getTagKind() << Record;
+ Complained = true;
+ }
+
+ Diag(F->getLocation(), diag::note_refconst_member_not_initialized)
+ << F->getType()->isReferenceType()
+ << F->getDeclName();
+ }
+ }
+ }
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2157,7 +2419,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
(DeclPtrTy*)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(
+ CheckCompletedCXXClass(S,
dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
}
@@ -2166,7 +2428,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// constructor, or destructor, to the given C++ class (C++
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
-void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
+///
+/// The scope, if provided, is the class scope.
+void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
+ CXXRecordDecl *ClassDecl) {
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
@@ -2197,7 +2462,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
- ClassDecl->addDecl(DefaultCon);
+ if (S)
+ PushOnScopeChains(DefaultCon, S, true);
+ else
+ ClassDecl->addDecl(DefaultCon);
}
if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
@@ -2278,9 +2546,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
CopyConstructor->setParams(&FromParam, 1);
- ClassDecl->addDecl(CopyConstructor);
+ if (S)
+ PushOnScopeChains(CopyConstructor, S, true);
+ else
+ ClassDecl->addDecl(CopyConstructor);
}
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
@@ -2354,7 +2626,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*FIXME:*/false,
false, 0, 0,
FunctionType::ExtInfo()),
- /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
+ /*TInfo=*/0, /*isStatic=*/false,
+ /*StorageClassAsWritten=*/FunctionDecl::None,
+ /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -2363,14 +2637,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
- /*IdentifierInfo=*/0,
+ /*Id=*/0,
ArgType, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
CopyAssignment->setParams(&FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
- ClassDecl->addDecl(CopyAssignment);
+ if (S)
+ PushOnScopeChains(CopyAssignment, S, true);
+ else
+ ClassDecl->addDecl(CopyAssignment);
AddOverriddenMethods(ClassDecl, CopyAssignment);
}
@@ -2394,7 +2672,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
- ClassDecl->addDecl(Destructor);
+ if (S)
+ PushOnScopeChains(Destructor, S, true);
+ else
+ ClassDecl->addDecl(Destructor);
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
@@ -2591,8 +2872,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
}
}
- // Notify the class that we've added a constructor.
- ClassDecl->addedConstructor(Context, Constructor);
+ // Notify the class that we've added a constructor. In principle we
+ // don't need to do this for out-of-line declarations; in practice
+ // we only instantiate the most recent declaration of a method, so
+ // we have to call this for everything but friends.
+ if (!Constructor->getFriendObjectKind())
+ ClassDecl->addedConstructor(Context, Constructor);
}
/// CheckDestructor - Checks a fully-formed destructor for well-formedness,
@@ -2737,6 +3022,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
SC = FunctionDecl::None;
}
+
+ QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
+
if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
// Conversion functions don't have return types, but the parser will
// happily parse something like:
@@ -2749,27 +3037,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
}
+ const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+
// Make sure we don't have any parameters.
- if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) {
+ if (Proto->getNumArgs() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
D.getTypeObject(0).Fun.freeArgs();
D.setInvalidType();
+ } else if (Proto->isVariadic()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ D.setInvalidType();
}
- // Make sure the conversion function isn't variadic.
- if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) {
- Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ // Diagnose "&operator bool()" and other such nonsense. This
+ // is actually a gcc extension which we don't support.
+ if (Proto->getResultType() != ConvType) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl)
+ << Proto->getResultType();
D.setInvalidType();
+ ConvType = Proto->getResultType();
}
// C++ [class.conv.fct]p4:
// The conversion-type-id shall not represent a function type nor
// an array type.
- QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
if (ConvType->isArrayType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
ConvType = Context.getPointerType(ConvType);
@@ -2783,14 +3079,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Rebuild the function type "R" without any parameters (in case any
// of the errors above fired) and with the conversion type as the
// return type.
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
- R = Context.getFunctionType(ConvType, 0, 0, false,
- Proto->getTypeQuals(),
- Proto->hasExceptionSpec(),
- Proto->hasAnyExceptionSpec(),
- Proto->getNumExceptions(),
- Proto->exception_begin(),
- Proto->getExtInfo());
+ if (D.isInvalidType()) {
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ Proto->getTypeQuals(),
+ Proto->hasExceptionSpec(),
+ Proto->hasAnyExceptionSpec(),
+ Proto->getNumExceptions(),
+ Proto->exception_begin(),
+ Proto->getExtInfo());
+ }
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -2886,7 +3183,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// in that declarative region, it is treated as an original-namespace-name.
NamedDecl *PrevDecl
- = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName,
+ = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName,
ForRedeclaration);
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
@@ -3013,7 +3310,7 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList) {
@@ -3082,7 +3379,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -3363,7 +3660,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
/// the lookup differently for these declarations.
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
@@ -3438,7 +3735,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (!LookupContext) return D;
UsingDecl *UD = cast<UsingDecl>(D);
- if (RequireCompleteDeclContext(SS)) {
+ if (RequireCompleteDeclContext(SS, LookupContext)) {
UD->setInvalidDecl();
return UD;
}
@@ -3700,7 +3997,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
@@ -3709,8 +4006,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
LookupParsedName(R, S, &SS);
// Check if we have a previous declaration with the same name.
- if (NamedDecl *PrevDecl
- = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) {
+ NamedDecl *PrevDecl
+ = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
+ ForRedeclaration);
+ if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+ PrevDecl = 0;
+
+ if (PrevDecl) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
@@ -3746,26 +4048,47 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
return DeclPtrTy::make(AliasDecl);
}
+namespace {
+ /// \brief Scoped object used to handle the state changes required in Sema
+ /// to implicitly define the body of a C++ member function;
+ class ImplicitlyDefinedFunctionScope {
+ Sema &S;
+ DeclContext *PreviousContext;
+
+ public:
+ ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method)
+ : S(S), PreviousContext(S.CurContext)
+ {
+ S.CurContext = Method;
+ S.PushFunctionScope();
+ S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ }
+
+ ~ImplicitlyDefinedFunctionScope() {
+ S.PopExpressionEvaluationContext();
+ S.PopFunctionOrBlockScope();
+ S.CurContext = PreviousContext;
+ }
+ };
+}
+
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
!Constructor->isUsed()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = Constructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
}
- CurContext = PreviousContext;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3775,8 +4098,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = Destructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
@@ -3788,114 +4110,429 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
Destructor->setInvalidDecl();
- CurContext = PreviousContext;
-
return;
}
- CurContext = PreviousContext;
Destructor->setUsed();
}
-void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
- CXXMethodDecl *MethodDecl) {
- assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal &&
- !MethodDecl->isUsed()) &&
- "DefineImplicitOverloadedAssign - call it for implicit assignment op");
+/// \brief Builds a statement that copies the given entity from \p From to
+/// \c To.
+///
+/// This routine is used to copy the members of a class with an
+/// implicitly-declared copy assignment operator. When the entities being
+/// copied are arrays, this routine builds for loops to copy them.
+///
+/// \param S The Sema object used for type-checking.
+///
+/// \param Loc The location where the implicit copy is being generated.
+///
+/// \param T The type of the expressions being copied. Both expressions must
+/// have this type.
+///
+/// \param To The expression we are copying to.
+///
+/// \param From The expression we are copying from.
+///
+/// \param Depth Internal parameter recording the depth of the recursion.
+///
+/// \returns A statement or a loop that copies the expressions.
+static Sema::OwningStmtResult
+BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
+ Sema::OwningExprResult To, Sema::OwningExprResult From,
+ unsigned Depth = 0) {
+ typedef Sema::OwningStmtResult OwningStmtResult;
+ typedef Sema::OwningExprResult OwningExprResult;
+
+ // C++0x [class.copy]p30:
+ // Each subobject is assigned in the manner appropriate to its type:
+ //
+ // - if the subobject is of class type, the copy assignment operator
+ // for the class is used (as if by explicit qualification; that is,
+ // ignoring any possible virtual overriding functions in more derived
+ // classes);
+ if (const RecordType *RecordTy = T->getAs<RecordType>()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+
+ // Look for operator=.
+ DeclarationName Name
+ = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName);
+ S.LookupQualifiedName(OpLookup, ClassDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = OpLookup.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Create the nested-name-specifier that will be used to qualify the
+ // reference to operator=; this is required to suppress the virtual
+ // call mechanism.
+ CXXScopeSpec SS;
+ SS.setRange(Loc);
+ SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false,
+ T.getTypePtr()));
+
+ // Create the reference to operator=.
+ OwningExprResult OpEqualRef
+ = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS,
+ /*FirstQualifierInScope=*/0, OpLookup,
+ /*TemplateArgs=*/0,
+ /*SuppressQualifierCheck=*/true);
+ if (OpEqualRef.isInvalid())
+ return S.StmtError();
+
+ // Build the call to the assignment operator.
+ Expr *FromE = From.takeAs<Expr>();
+ OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
+ OpEqualRef.takeAs<Expr>(),
+ Loc, &FromE, 1, 0, Loc);
+ if (Call.isInvalid())
+ return S.StmtError();
+
+ return S.Owned(Call.takeAs<Stmt>());
+ }
+
+ // - if the subobject is of scalar type, the built-in assignment
+ // operator is used.
+ const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
+ if (!ArrayTy) {
+ OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc,
+ BinaryOperator::Assign,
+ To.takeAs<Expr>(),
+ From.takeAs<Expr>());
+ if (Assignment.isInvalid())
+ return S.StmtError();
+
+ return S.Owned(Assignment.takeAs<Stmt>());
+ }
+
+ // - if the subobject is an array, each element is assigned, in the
+ // manner appropriate to the element type;
+
+ // Construct a loop over the array bounds, e.g.,
+ //
+ // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
+ //
+ // that will copy each of the array elements.
+ QualType SizeType = S.Context.getSizeType();
+
+ // Create the iteration variable.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ llvm::SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << Depth;
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc,
+ IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ VarDecl::None, VarDecl::None);
+
+ // Initialize the iteration variable to zero.
+ llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
+ IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc));
+
+ // Create a reference to the iteration variable; we'll use this several
+ // times throughout.
+ Expr *IterationVarRef
+ = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>();
+ assert(IterationVarRef && "Reference to invented variable cannot fail!");
+
+ // Create the DeclStmt that holds the iteration variable.
+ Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
+
+ // Create the comparison against the array bound.
+ llvm::APInt Upper = ArrayTy->getSize();
+ Upper.zextOrTrunc(S.Context.getTypeSize(SizeType));
+ OwningExprResult Comparison
+ = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(),
+ new (S.Context) IntegerLiteral(Upper, SizeType, Loc),
+ BinaryOperator::NE, S.Context.BoolTy, Loc));
+
+ // Create the pre-increment of the iteration variable.
+ OwningExprResult Increment
+ = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(),
+ UnaryOperator::PreInc,
+ SizeType, Loc));
+
+ // Subscript the "from" and "to" expressions with the iteration variable.
+ From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc,
+ S.Owned(IterationVarRef->Retain()),
+ Loc);
+ To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc,
+ S.Owned(IterationVarRef->Retain()),
+ Loc);
+ assert(!From.isInvalid() && "Builtin subscripting can't fail!");
+ assert(!To.isInvalid() && "Builtin subscripting can't fail!");
+
+ // Build the copy for an individual element of the array.
+ OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc,
+ ArrayTy->getElementType(),
+ move(To), move(From), Depth+1);
+ if (Copy.isInvalid()) {
+ InitStmt->Destroy(S.Context);
+ return S.StmtError();
+ }
+
+ // Construct the loop that copies all elements of this array.
+ return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt),
+ S.MakeFullExpr(Comparison),
+ Sema::DeclPtrTy(),
+ S.MakeFullExpr(Increment),
+ Loc, move(Copy));
+}
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *CopyAssignOperator) {
+ assert((CopyAssignOperator->isImplicit() &&
+ CopyAssignOperator->isOverloadedOperator() &&
+ CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
+ !CopyAssignOperator->isUsed()) &&
+ "DefineImplicitCopyAssignment called for wrong function");
+
+ CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
- DeclContext *PreviousContext = CurContext;
- CurContext = MethodDecl;
+ if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) {
+ CopyAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ CopyAssignOperator->setUsed();
- // C++[class.copy] p12
- // Before the implicitly-declared copy assignment operator for a class is
- // implicitly defined, all implicitly-declared copy assignment operators
- // for its direct base classes and its nonstatic data members shall have
- // been implicitly defined.
- bool err = false;
+ ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+
+ // C++0x [class.copy]p30:
+ // The implicitly-defined or explicitly-defaulted copy assignment operator
+ // for a non-union class X performs memberwise copy assignment of its
+ // subobjects. The direct base classes of X are assigned first, in the
+ // order of their declaration in the base-specifier-list, and then the
+ // immediate non-static data members of X are assigned, in the order in
+ // which they were declared in the class definition.
+
+ // The statements that form the synthesized function body.
+ ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this);
+
+ // The parameter for the "other" object, which we are copying from.
+ ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
+ Qualifiers OtherQuals = Other->getType().getQualifiers();
+ QualType OtherRefType = Other->getType();
+ if (const LValueReferenceType *OtherRef
+ = OtherRefType->getAs<LValueReferenceType>()) {
+ OtherRefType = OtherRef->getPointeeType();
+ OtherQuals = OtherRefType.getQualifiers();
+ }
+
+ // Our location for everything implicitly-generated.
+ SourceLocation Loc = CopyAssignOperator->getLocation();
+
+ // Construct a reference to the "other" object. We'll be using this
+ // throughout the generated ASTs.
+ Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>();
+ assert(OtherRef && "Reference to parameter cannot fail!");
+
+ // Construct the "this" pointer. We'll be using this throughout the generated
+ // ASTs.
+ Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
+ assert(This && "Reference to this cannot fail!");
+
+ // Assign base classes.
+ bool Invalid = false;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *BaseAssignOpMethod =
- getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- BaseClassDecl)) {
- CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
- BaseAssignOpMethod,
- PDiag(diag::err_access_assign_base)
- << Base->getType());
-
- MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ // Form the assignment:
+ // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other));
+ QualType BaseType = Base->getType().getUnqualifiedType();
+ CXXRecordDecl *BaseClassDecl = 0;
+ if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>())
+ BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl());
+ else {
+ Invalid = true;
+ continue;
+ }
+
+ // Construct the "from" expression, which is an implicit cast to the
+ // appropriately-qualified base type.
+ Expr *From = OtherRef->Retain();
+ ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals),
+ CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true,
+ CXXBaseSpecifierArray(Base));
+
+ // Dereference "this".
+ OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref,
+ Owned(This->Retain()));
+
+ // Implicitly cast "this" to the appropriately-qualified base type.
+ Expr *ToE = To.takeAs<Expr>();
+ ImpCastExprToType(ToE,
+ Context.getCVRQualifiedType(BaseType,
+ CopyAssignOperator->getTypeQualifiers()),
+ CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/true, CXXBaseSpecifierArray(Base));
+ To = Owned(ToE);
+
+ // Build the copy.
+ OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
+ move(To), Owned(From));
+ if (Copy.isInvalid()) {
+ Invalid = true;
+ continue;
}
+
+ // Success! Record the copy.
+ Statements.push_back(Copy.takeAs<Expr>());
}
+
+ // \brief Reference to the __builtin_memcpy function.
+ Expr *BuiltinMemCpyRef = 0;
+
+ // Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXMethodDecl *FieldAssignOpMethod =
- getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- FieldClassDecl)) {
- CheckDirectMemberAccess(Field->getLocation(),
- FieldAssignOpMethod,
- PDiag(diag::err_access_assign_field)
- << Field->getDeclName() << Field->getType());
-
- MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
- }
- } else if (FieldType->isReferenceType()) {
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ // Check for members of reference type; we can't copy those.
+ if (Field->getType()->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_first_required_here);
- err = true;
- } else if (FieldType.isConstQualified()) {
+ Diag(Loc, diag::note_first_required_here);
+ Invalid = true;
+ continue;
+ }
+
+ // Check for members of const-qualified, non-class type.
+ QualType BaseType = Context.getBaseElementType(Field->getType());
+ if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_first_required_here);
- err = true;
+ Diag(Loc, diag::note_first_required_here);
+ Invalid = true;
+ continue;
}
+
+ QualType FieldType = Field->getType().getNonReferenceType();
+
+ // Build references to the field in the object we're copying from and to.
+ CXXScopeSpec SS; // Intentionally empty
+ LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
+ LookupMemberName);
+ MemberLookup.addDecl(*Field);
+ MemberLookup.resolveKind();
+ OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()),
+ OtherRefType,
+ Loc, /*IsArrow=*/false,
+ SS, 0, MemberLookup, 0);
+ OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()),
+ This->getType(),
+ Loc, /*IsArrow=*/true,
+ SS, 0, MemberLookup, 0);
+ assert(!From.isInvalid() && "Implicit field reference cannot fail");
+ assert(!To.isInvalid() && "Implicit field reference cannot fail");
+
+ // If the field should be copied with __builtin_memcpy rather than via
+ // explicit assignments, do so. This optimization only applies for arrays
+ // of scalars and arrays of class type with trivial copy-assignment
+ // operators.
+ if (FieldType->isArrayType() &&
+ (!BaseType->isRecordType() ||
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl())
+ ->hasTrivialCopyAssignment())) {
+ // Compute the size of the memory buffer to be copied.
+ QualType SizeType = Context.getSizeType();
+ llvm::APInt Size(Context.getTypeSize(SizeType),
+ Context.getTypeSizeInChars(BaseType).getQuantity());
+ for (const ConstantArrayType *Array
+ = Context.getAsConstantArrayType(FieldType);
+ Array;
+ Array = Context.getAsConstantArrayType(Array->getElementType())) {
+ llvm::APInt ArraySize = Array->getSize();
+ ArraySize.zextOrTrunc(Size.getBitWidth());
+ Size *= ArraySize;
+ }
+
+ // Take the address of the field references for "from" and "to".
+ From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From));
+ To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To));
+
+ // Create a reference to the __builtin_memcpy builtin function.
+ if (!BuiltinMemCpyRef) {
+ LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
+ LookupOrdinaryName);
+ LookupName(R, TUScope, true);
+
+ FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
+ if (!BuiltinMemCpy) {
+ // Something went horribly wrong earlier, and we will have complained
+ // about it.
+ Invalid = true;
+ continue;
+ }
+
+ BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
+ BuiltinMemCpy->getType(),
+ Loc, 0).takeAs<Expr>();
+ assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
+ }
+
+ ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this);
+ CallArgs.push_back(To.takeAs<Expr>());
+ CallArgs.push_back(From.takeAs<Expr>());
+ CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc));
+ llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly
+ Commas.push_back(Loc);
+ Commas.push_back(Loc);
+ OwningExprResult Call = ActOnCallExpr(/*Scope=*/0,
+ Owned(BuiltinMemCpyRef->Retain()),
+ Loc, move_arg(CallArgs),
+ Commas.data(), Loc);
+ assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
+ Statements.push_back(Call.takeAs<Expr>());
+ continue;
+ }
+
+ // Build the copy of this field.
+ OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType,
+ move(To), move(From));
+ if (Copy.isInvalid()) {
+ Invalid = true;
+ continue;
+ }
+
+ // Success! Record the copy.
+ Statements.push_back(Copy.takeAs<Stmt>());
}
- if (!err)
- MethodDecl->setUsed();
- CurContext = PreviousContext;
-}
+ if (!Invalid) {
+ // Add a "return *this;"
+ OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref,
+ Owned(This->Retain()));
+
+ OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj));
+ if (Return.isInvalid())
+ Invalid = true;
+ else {
+ Statements.push_back(Return.takeAs<Stmt>());
+ }
+ }
-CXXMethodDecl *
-Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
- ParmVarDecl *ParmDecl,
- CXXRecordDecl *ClassDecl) {
- QualType LHSType = Context.getTypeDeclType(ClassDecl);
- QualType RHSType(LHSType);
- // If class's assignment operator argument is const/volatile qualified,
- // look for operator = (const/volatile B&). Otherwise, look for
- // operator = (B&).
- RHSType = Context.getCVRQualifiedType(RHSType,
- ParmDecl->getType().getCVRQualifiers());
- ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
- SourceLocation()));
- ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
- CurrentLocation));
- Expr *Args[2] = { &*LHS, &*RHS };
- OverloadCandidateSet CandidateSet(CurrentLocation);
- AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
- CandidateSet);
- OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success)
- return cast<CXXMethodDecl>(Best->Function);
- assert(false &&
- "getAssignOperatorMethod - copy assignment operator method not found");
- return 0;
+ if (Invalid) {
+ CopyAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ /*isStmtExpr=*/false);
+ assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+ CopyAssignOperator->setBody(Body.takeAs<Stmt>());
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -3906,32 +4543,21 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
!CopyConstructor->isUsed()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = CopyConstructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
- // C++ [class.copy] p209
- // Before the implicitly-declared copy constructor for a class is
- // implicitly defined, all the implicitly-declared copy constructors
- // for its base class and its non-static data members shall have been
- // implicitly defined.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
- CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
- BaseCopyCtor,
- PDiag(diag::err_access_copy_base)
- << Base->getType());
-
- MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
- }
+ if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ CopyConstructor->setInvalidDecl();
+ } else {
+ CopyConstructor->setUsed();
}
+
+ // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of
+ // fields, this code below should be removed.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd; ++Field) {
@@ -3952,9 +4578,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
}
- CopyConstructor->setUsed();
-
- CurContext = PreviousContext;
}
Sema::OwningExprResult
@@ -3962,7 +4585,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool RequiresZeroInit,
- bool BaseInitialization) {
+ CXXConstructExpr::ConstructionKind ConstructKind) {
bool Elidable = false;
// C++0x [class.copy]p34:
@@ -3984,7 +4607,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, move(ExprArgs), RequiresZeroInit,
- BaseInitialization);
+ ConstructKind);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3994,14 +4617,14 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
bool RequiresZeroInit,
- bool BaseInitialization) {
+ CXXConstructExpr::ConstructionKind ConstructKind) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit, BaseInitialization));
+ RequiresZeroInit, ConstructKind));
}
bool Sema::InitializeVarWithConstructor(VarDecl *VD,
@@ -4138,113 +4761,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
FinalizeVarWithDestructor(VDecl, Record);
}
-/// \brief Add the applicable constructor candidates for an initialization
-/// by constructor.
-static void AddConstructorInitializationCandidates(Sema &SemaRef,
- QualType ClassType,
- Expr **Args,
- unsigned NumArgs,
- InitializationKind Kind,
- OverloadCandidateSet &CandidateSet) {
- // C++ [dcl.init]p14:
- // If the initialization is direct-initialization, or if it is
- // copy-initialization where the cv-unqualified version of the
- // source type is the same class as, or a derived class of, the
- // class of the destination, constructors are considered. The
- // applicable constructors are enumerated (13.3.1.3), and the
- // best one is chosen through overload resolution (13.3). The
- // constructor so selected is called to initialize the object,
- // with the initializer expression(s) as its argument(s). If no
- // constructor applies, or the overload resolution is ambiguous,
- // the initialization is ill-formed.
- const RecordType *ClassRec = ClassType->getAs<RecordType>();
- assert(ClassRec && "Can only initialize a class type here");
-
- // FIXME: When we decide not to synthesize the implicitly-declared
- // constructors, we'll need to make them appear here.
-
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
- DeclarationName ConstructorName
- = SemaRef.Context.DeclarationNames.getCXXConstructorName(
- SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType());
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
- if (ConstructorTmpl)
- Constructor
- = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(*Con);
-
- if ((Kind.getKind() == InitializationKind::IK_Direct) ||
- (Kind.getKind() == InitializationKind::IK_Value) ||
- (Kind.getKind() == InitializationKind::IK_Copy &&
- Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
- ((Kind.getKind() == InitializationKind::IK_Default) &&
- Constructor->isDefaultConstructor())) {
- if (ConstructorTmpl)
- SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet);
- else
- SemaRef.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet);
- }
- }
-}
-
-/// \brief Attempt to perform initialization by constructor
-/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or
-/// copy-initialization.
-///
-/// This routine determines whether initialization by constructor is possible,
-/// but it does not emit any diagnostics in the case where the initialization
-/// is ill-formed.
-///
-/// \param ClassType the type of the object being initialized, which must have
-/// class type.
-///
-/// \param Args the arguments provided to initialize the object
-///
-/// \param NumArgs the number of arguments provided to initialize the object
-///
-/// \param Kind the type of initialization being performed
-///
-/// \returns the constructor used to initialize the object, if successful.
-/// Otherwise, emits a diagnostic and returns NULL.
-CXXConstructorDecl *
-Sema::TryInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
- SourceLocation Loc,
- InitializationKind Kind) {
- // Build the overload candidate set
- OverloadCandidateSet CandidateSet(Loc);
- AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
- CandidateSet);
-
- // Determine whether we found a constructor we can use.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Loc, Best)) {
- case OR_Success:
- case OR_Deleted:
- // We found a constructor. Return it.
- return cast<CXXConstructorDecl>(Best->Function);
-
- case OR_No_Viable_Function:
- case OR_Ambiguous:
- // Overload resolution failed. Return nothing.
- return 0;
- }
-
- // Silence GCC warning
- return 0;
-}
-
/// \brief Given a constructor and the set of arguments provided for the
/// constructor, convert the arguments and add any required default arguments
/// to form a proper call to this constructor.
@@ -4281,472 +4797,6 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
return Invalid;
}
-/// CompareReferenceRelationship - Compare the two types T1 and T2 to
-/// determine whether they are reference-related,
-/// reference-compatible, reference-compatible with added
-/// qualification, or incompatible, for use in C++ initialization by
-/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
-/// type, and the first type (T1) is the pointee type of the reference
-/// type being initialized.
-Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(SourceLocation Loc,
- QualType OrigT1, QualType OrigT2,
- bool& DerivedToBase) {
- assert(!OrigT1->isReferenceType() &&
- "T1 must be the pointee type of the reference type");
- assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
-
- QualType T1 = Context.getCanonicalType(OrigT1);
- QualType T2 = Context.getCanonicalType(OrigT2);
- Qualifiers T1Quals, T2Quals;
- QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
- QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
- // reference-related to "cv2 T2" if T1 is the same type as T2, or
- // T1 is a base class of T2.
- if (UnqualT1 == UnqualT2)
- DerivedToBase = false;
- else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
- !RequireCompleteType(Loc, OrigT2, PDiag()) &&
- IsDerivedFrom(UnqualT2, UnqualT1))
- DerivedToBase = true;
- else
- return Ref_Incompatible;
-
- // At this point, we know that T1 and T2 are reference-related (at
- // least).
-
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = Context.getQualifiedType(UnqualT2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
- // reference-related to T2 and cv1 is the same cv-qualification
- // as, or greater cv-qualification than, cv2. For purposes of
- // overload resolution, cases for which cv1 is greater
- // cv-qualification than cv2 are identified as
- // reference-compatible with added qualification (see 13.3.3.2).
- if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
- return Ref_Compatible;
- else if (T1.isMoreQualifiedThan(T2))
- return Ref_Compatible_With_Added_Qualification;
- else
- return Ref_Related;
-}
-
-/// CheckReferenceInit - Check the initialization of a reference
-/// variable with the given initializer (C++ [dcl.init.ref]). Init is
-/// the initializer (either a simple initializer or an initializer
-/// list), and DeclType is the type of the declaration. When ICS is
-/// non-null, this routine will compute the implicit conversion
-/// sequence according to C++ [over.ics.ref] and will not produce any
-/// diagnostics; when ICS is null, it will emit diagnostics when any
-/// errors are found. Either way, a return value of true indicates
-/// that there was a failure, a return value of false indicates that
-/// the reference initialization succeeded.
-///
-/// When @p SuppressUserConversions, user-defined conversions are
-/// suppressed.
-/// When @p AllowExplicit, we also permit explicit user-defined
-/// conversion functions.
-/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
-/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion.
-/// This is used when this is called from a C-style cast.
-bool
-Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
- SourceLocation DeclLoc,
- bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue,
- ImplicitConversionSequence *ICS,
- bool IgnoreBaseAccess) {
- assert(DeclType->isReferenceType() && "Reference init needs a reference");
-
- QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
- QualType T2 = Init->getType();
-
- // If the initializer is the address of an overloaded function, try
- // to resolve the overloaded function. If all goes well, T2 is the
- // type of the resulting function.
- if (Context.getCanonicalType(T2) == Context.OverloadTy) {
- DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
- ICS != 0, Found);
- if (Fn) {
- // Since we're performing this reference-initialization for
- // real, update the initializer with the resulting function.
- if (!ICS) {
- if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
-
- CheckAddressOfMemberAccess(Init, Found);
- Init = FixOverloadedFunctionReference(Init, Found, Fn);
- }
-
- T2 = Fn->getType();
- }
- }
-
- // Compute some basic properties of the types and the initializer.
- bool isRValRef = DeclType->isRValueReferenceType();
- bool DerivedToBase = false;
- Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
- Init->isLvalue(Context);
- ReferenceCompareResult RefRelationship
- = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
-
- // Most paths end in a failed conversion.
- if (ICS) {
- ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType);
- }
-
- // C++ [dcl.init.ref]p5:
- // A reference to type "cv1 T1" is initialized by an expression
- // of type "cv2 T2" as follows:
-
- // -- If the initializer expression
-
- // Rvalue references cannot bind to lvalues (N2812).
- // There is absolutely no situation where they can. In particular, note that
- // this is ill-formed, even if B has a user-defined conversion to A&&:
- // B b;
- // A&& r = b;
- if (isRValRef && InitLvalue == Expr::LV_Valid) {
- if (!ICS)
- Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
- << Init->getSourceRange();
- return true;
- }
-
- bool BindsDirectly = false;
- // -- is an lvalue (but is not a bit-field), and "cv1 T1" is
- // reference-compatible with "cv2 T2," or
- //
- // Note that the bit-field check is skipped if we are just computing
- // the implicit conversion sequence (C++ [over.best.ics]p2).
- if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) &&
- RefRelationship >= Ref_Compatible_With_Added_Qualification) {
- BindsDirectly = true;
-
- if (ICS) {
- // C++ [over.ics.ref]p1:
- // When a parameter of reference type binds directly (8.5.3)
- // to an argument expression, the implicit conversion sequence
- // is the identity conversion, unless the argument expression
- // has a type that is a derived class of the parameter type,
- // in which case the implicit conversion sequence is a
- // derived-to-base Conversion (13.3.3.1).
- ICS->setStandard();
- ICS->Standard.First = ICK_Identity;
- ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
- ICS->Standard.Third = ICK_Identity;
- ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.setToType(0, T2);
- ICS->Standard.setToType(1, T1);
- ICS->Standard.setToType(2, T1);
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.DirectBinding = true;
- ICS->Standard.RRefBinding = false;
- ICS->Standard.CopyConstructor = 0;
-
- // Nothing more to do: the inaccessibility/ambiguity check for
- // derived-to-base conversions is suppressed when we're
- // computing the implicit conversion sequence (C++
- // [over.best.ics]p2).
- return false;
- } else {
- // Perform the conversion.
- CastExpr::CastKind CK = CastExpr::CK_NoOp;
- if (DerivedToBase)
- CK = CastExpr::CK_DerivedToBase;
- else if(CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true);
- }
- }
-
- // -- has a class type (i.e., T2 is a class type) and can be
- // implicitly converted to an lvalue of type "cv3 T3,"
- // where "cv1 T1" is reference-compatible with "cv3 T3"
- // 92) (this conversion is selected by enumerating the
- // applicable conversion functions (13.3.1.6) and choosing
- // the best one through overload resolution (13.3)),
- if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
- !RequireCompleteType(DeclLoc, T2, 0)) {
- CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
-
- OverloadCandidateSet CandidateSet(DeclLoc);
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::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>(D);
- CXXConversionDecl *Conv;
- if (ConvTemplate)
- Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
- else
- 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, I.getPair(), ActingDC,
- Init, DeclType, CandidateSet);
- else
- AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
- DeclType, CandidateSet);
- }
- }
-
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, DeclLoc, Best)) {
- case OR_Success:
- // C++ [over.ics.ref]p1:
- //
- // [...] If the parameter binds directly to the result of
- // applying a conversion function to the argument
- // expression, the implicit conversion sequence is a
- // user-defined conversion sequence (13.3.3.1.2), with the
- // second standard conversion sequence either an identity
- // conversion or, if the conversion function returns an
- // entity of a type that is a derived class of the parameter
- // type, a derived-to-base Conversion.
- if (!Best->FinalConversion.DirectBinding)
- break;
-
- // This is a direct binding.
- BindsDirectly = true;
-
- if (ICS) {
- ICS->setUserDefined();
- ICS->UserDefined.Before = Best->Conversions[0].Standard;
- ICS->UserDefined.After = Best->FinalConversion;
- ICS->UserDefined.ConversionFunction = Best->Function;
- ICS->UserDefined.EllipsisConversion = false;
- assert(ICS->UserDefined.After.ReferenceBinding &&
- ICS->UserDefined.After.DirectBinding &&
- "Expected a direct reference binding!");
- return false;
- } else {
- OwningExprResult InitConversion =
- BuildCXXCastArgument(DeclLoc, QualType(),
- CastExpr::CK_UserDefinedConversion,
- cast<CXXMethodDecl>(Best->Function),
- Owned(Init));
- Init = InitConversion.takeAs<Expr>();
-
- if (CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion,
- /*isLvalue=*/true);
- }
- break;
-
- case OR_Ambiguous:
- if (ICS) {
- ICS->setAmbiguous();
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
- Cand != CandidateSet.end(); ++Cand)
- if (Cand->Viable)
- ICS->Ambiguous.addConversion(Cand->Function);
- break;
- }
- Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
- << Init->getSourceRange();
- PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1);
- return true;
-
- case OR_No_Viable_Function:
- case OR_Deleted:
- // There was no suitable conversion, or we found a deleted
- // conversion; continue with other checks.
- break;
- }
- }
-
- if (BindsDirectly) {
- // C++ [dcl.init.ref]p4:
- // [...] In all cases where the reference-related or
- // reference-compatible relationship of two types is used to
- // establish the validity of a reference binding, and T1 is a
- // base class of T2, a program that necessitates such a binding
- // is ill-formed if T1 is an inaccessible (clause 11) or
- // ambiguous (10.2) base class of T2.
- //
- // Note that we only check this condition when we're allowed to
- // complain about errors, because we should not be checking for
- // ambiguity (or inaccessibility) unless the reference binding
- // actually happens.
- if (DerivedToBase)
- return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
- Init->getSourceRange(),
- IgnoreBaseAccess);
- else
- return false;
- }
-
- // -- Otherwise, the reference shall be to a non-volatile const
- // type (i.e., cv1 shall be const), or the reference shall be an
- // rvalue reference and the initializer expression shall be an rvalue.
- if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
- if (!ICS)
- Diag(DeclLoc, diag::err_not_reference_to_const_init)
- << T1.isVolatileQualified()
- << T1 << int(InitLvalue != Expr::LV_Valid)
- << T2 << Init->getSourceRange();
- return true;
- }
-
- // -- If the initializer expression is an rvalue, with T2 a
- // class type, and "cv1 T1" is reference-compatible with
- // "cv2 T2," the reference is bound in one of the
- // following ways (the choice is implementation-defined):
- //
- // -- The reference is bound to the object represented by
- // the rvalue (see 3.10) or to a sub-object within that
- // object.
- //
- // -- A temporary of type "cv1 T2" [sic] is created, and
- // a constructor is called to copy the entire rvalue
- // object into the temporary. The reference is bound to
- // the temporary or to a sub-object within the
- // temporary.
- //
- // The constructor that would be used to make the copy
- // shall be callable whether or not the copy is actually
- // done.
- //
- // Note that C++0x [dcl.init.ref]p5 takes away this implementation
- // freedom, so we will always take the first option and never build
- // a temporary in this case. FIXME: We will, however, have to check
- // for the presence of a copy constructor in C++98/03 mode.
- if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
- RefRelationship >= Ref_Compatible_With_Added_Qualification) {
- if (ICS) {
- ICS->setStandard();
- ICS->Standard.First = ICK_Identity;
- ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
- ICS->Standard.Third = ICK_Identity;
- ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.setToType(0, T2);
- ICS->Standard.setToType(1, T1);
- ICS->Standard.setToType(2, T1);
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.DirectBinding = false;
- ICS->Standard.RRefBinding = isRValRef;
- ICS->Standard.CopyConstructor = 0;
- } else {
- CastExpr::CastKind CK = CastExpr::CK_NoOp;
- if (DerivedToBase)
- CK = CastExpr::CK_DerivedToBase;
- else if(CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false);
- }
- return false;
- }
-
- // -- Otherwise, a temporary of type "cv1 T1" is created and
- // initialized from the initializer expression using the
- // rules for a non-reference copy initialization (8.5). The
- // reference is then bound to the temporary. If T1 is
- // reference-related to T2, cv1 must be the same
- // cv-qualification as, or greater cv-qualification than,
- // cv2; otherwise, the program is ill-formed.
- if (RefRelationship == Ref_Related) {
- // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
- // we would be reference-compatible or reference-compatible with
- // added qualification. But that wasn't the case, so the reference
- // initialization fails.
- if (!ICS)
- Diag(DeclLoc, diag::err_reference_init_drops_quals)
- << T1 << int(InitLvalue != Expr::LV_Valid)
- << T2 << Init->getSourceRange();
- return true;
- }
-
- // If at least one of the types is a class type, the types are not
- // related, and we aren't allowed any user conversions, the
- // reference binding fails. This case is important for breaking
- // recursion, since TryImplicitConversion below will attempt to
- // create a temporary through the use of a copy constructor.
- if (SuppressUserConversions && RefRelationship == Ref_Incompatible &&
- (T1->isRecordType() || T2->isRecordType())) {
- if (!ICS)
- Diag(DeclLoc, diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange();
- return true;
- }
-
- // Actually try to convert the initializer to T1.
- if (ICS) {
- // C++ [over.ics.ref]p2:
- //
- // When a parameter of reference type is not bound directly to
- // an argument expression, the conversion sequence is the one
- // required to convert the argument expression to the
- // underlying type of the reference according to
- // 13.3.3.1. Conceptually, this conversion sequence corresponds
- // to copy-initializing a temporary of the underlying type with
- // the argument expression. Any difference in top-level
- // cv-qualification is subsumed by the initialization itself
- // and does not constitute a conversion.
- *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- // Of course, that's still a reference binding.
- if (ICS->isStandard()) {
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.RRefBinding = isRValRef;
- } else if (ICS->isUserDefined()) {
- ICS->UserDefined.After.ReferenceBinding = true;
- ICS->UserDefined.After.RRefBinding = isRValRef;
- }
- return ICS->isBad();
- } else {
- ImplicitConversionSequence Conversions;
- bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing,
- false, false,
- Conversions);
- if (badConversion) {
- if (Conversions.isAmbiguous()) {
- Diag(DeclLoc,
- diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
- for (int j = Conversions.Ambiguous.conversions().size()-1;
- j >= 0; j--) {
- FunctionDecl *Func = Conversions.Ambiguous.conversions()[j];
- NoteOverloadCandidate(Func);
- }
- }
- else {
- if (isRValRef)
- Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
- << Init->getSourceRange();
- else
- Diag(DeclLoc, diag::err_invalid_initialization)
- << DeclType << Init->getType() << Init->getSourceRange();
- }
- }
- return badConversion;
- }
-}
-
static inline bool
CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
const FunctionDecl *FnDecl) {
@@ -5044,17 +5094,32 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
bool Valid = false;
- // FIXME: Check for the one valid template signature
- // template <char...> type operator "" name();
-
- if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
+ // template <char...> type operator "" name() is the only valid template
+ // signature, and the only valid signature with no parameters.
+ if (FnDecl->param_size() == 0) {
+ if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
+ // Must have only one template parameter
+ TemplateParameterList *Params = TpDecl->getTemplateParameters();
+ if (Params->size() == 1) {
+ NonTypeTemplateParmDecl *PmDecl =
+ cast<NonTypeTemplateParmDecl>(Params->getParam(0));
+
+ // The template parameter must be a char parameter pack.
+ // FIXME: This test will always fail because non-type parameter packs
+ // have not been implemented.
+ if (PmDecl && PmDecl->isTemplateParameterPack() &&
+ Context.hasSameType(PmDecl->getType(), Context.CharTy))
+ Valid = true;
+ }
+ }
+ } else {
// Check the first parameter
+ FunctionDecl::param_iterator Param = FnDecl->param_begin();
+
QualType T = (*Param)->getType();
- // unsigned long long int and long double are allowed, but only
- // alone.
- // We also allow any character type; their omission seems to be a bug
- // in n3000
+ // unsigned long long int, long double, and any character type are allowed
+ // as the only parameters.
if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
Context.hasSameType(T, Context.LongDoubleTy) ||
Context.hasSameType(T, Context.CharTy) ||
@@ -5066,7 +5131,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
goto FinishedParams;
}
- // Otherwise it must be a pointer to const; let's strip those.
+ // Otherwise it must be a pointer to const; let's strip those qualifiers.
const PointerType *PT = T->getAs<PointerType>();
if (!PT)
goto FinishedParams;
@@ -5121,13 +5186,12 @@ FinishedParams:
Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- const char *Lang,
- unsigned StrSize,
+ llvm::StringRef Lang,
SourceLocation LBraceLoc) {
LinkageSpecDecl::LanguageIDs Language;
- if (strncmp(Lang, "\"C\"", StrSize) == 0)
+ if (Lang == "\"C\"")
Language = LinkageSpecDecl::lang_c;
- else if (strncmp(Lang, "\"C++\"", StrSize) == 0)
+ else if (Lang == "\"C++\"")
Language = LinkageSpecDecl::lang_cxx;
else {
Diag(LangLoc, diag::err_bad_language);
@@ -5212,8 +5276,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
Invalid = true;
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, TInfo, VarDecl::None);
-
+ Name, ExDeclType, TInfo, VarDecl::None,
+ VarDecl::None);
+ ExDecl->setExceptionVariable(true);
+
if (!Invalid) {
if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) {
// C++ [except.handle]p16:
@@ -5254,7 +5320,9 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
- if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
+ if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(),
+ LookupOrdinaryName,
+ ForRedeclaration)) {
// The scope should be freshly made just for us. There is just no way
// it contains any previous declaration.
assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl)));
@@ -5318,6 +5386,62 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
return DeclPtrTy::make(Decl);
}
+/// \brief Perform semantic analysis of the given friend type declaration.
+///
+/// \returns A friend declaration that.
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
+ TypeSourceInfo *TSInfo) {
+ assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
+
+ QualType T = TSInfo->getType();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
+
+ if (!getLangOptions().CPlusPlus0x) {
+ // C++03 [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ //
+ // * The class-key of the elaborated-type-specifier is required.
+ if (!ActiveTemplateInstantiations.empty()) {
+ // Do not complain about the form of friend template types during
+ // template instantiation; we will already have complained when the
+ // template was declared.
+ } else if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc, diag::ext_nonclass_type_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ } else if (T->getAs<EnumType>()) {
+ Diag(FriendLoc, diag::ext_enum_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ }
+
+ // C++0x [class.friend]p3:
+ // If the type specifier in a friend declaration designates a (possibly
+ // cv-qualified) class type, that class is declared as a friend; otherwise,
+ // the friend declaration is ignored.
+
+ // FIXME: C++0x has some syntactic restrictions on friend type declarations
+ // in [class.friend]p3 that we do not implement.
+
+ return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
+}
+
/// Handle a friend type declaration. This works in tandem with
/// ActOnTag.
///
@@ -5351,6 +5475,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (TheDeclarator.isInvalidType())
return DeclPtrTy();
+ if (!TSI)
+ TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin());
+
// This is definitely an error in C++98. It's probably meant to
// be forbidden in C++0x, too, but the specification is just
// poorly written.
@@ -5370,41 +5497,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< DS.getSourceRange();
return DeclPtrTy();
}
-
- // C++ [class.friend]p2:
- // An elaborated-type-specifier shall be used in a friend declaration
- // for a class.*
- // * The class-key of the elaborated-type-specifier is required.
- // This is one of the rare places in Clang where it's legitimate to
- // ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
-
- std::string InsertionText = std::string(" ") + RD->getKindName();
-
- Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
- << T
- << SourceRange(DS.getFriendSpecLoc())
- << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
- return DeclPtrTy();
- }else {
- Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
- << DS.getSourceRange();
- return DeclPtrTy();
- }
- }
-
- // Enum types cannot be friends.
- if (T->getAs<EnumType>()) {
- Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
- << SourceRange(DS.getFriendSpecLoc());
- return DeclPtrTy();
- }
-
+
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
// This is fixed in DR77, which just barely didn't make the C++03
@@ -5417,15 +5510,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend a member of an arbitrary specialization of your template).
Decl *D;
- if (TempParams.size())
+ if (unsigned NumTempParamLists = TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
- TempParams.size(),
+ NumTempParamLists,
(TemplateParameterList**) TempParams.release(),
TSI,
DS.getFriendSpecLoc());
else
- D = FriendDecl::Create(Context, CurContext, Loc, TSI,
- DS.getFriendSpecLoc());
+ D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI);
+
+ if (!D)
+ return DeclPtrTy();
+
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -5493,11 +5589,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName,
ForRedeclaration);
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
- // FIXME: RequireCompleteDeclContext
DC = computeDeclContext(ScopeQual);
// FIXME: handle dependent contexts
if (!DC) return DeclPtrTy();
+ if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy();
LookupQualifiedName(Previous, DC);
@@ -5595,9 +5691,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
- if (D.getName().getKind() == UnqualifiedId::IK_TemplateId)
- FrD->setSpecialization(true);
-
return DeclPtrTy::make(ND);
}
@@ -5701,10 +5794,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
// Check if we the conversion from derived to base is valid.
if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
- diag::err_covariant_return_inaccessible_base,
- diag::err_covariant_return_ambiguous_derived_to_base_conv,
- // FIXME: Should this point to the return type?
- New->getLocation(), SourceRange(), New->getDeclName())) {
+ diag::err_covariant_return_inaccessible_base,
+ diag::err_covariant_return_ambiguous_derived_to_base_conv,
+ // FIXME: Should this point to the return type?
+ New->getLocation(), SourceRange(), New->getDeclName(), 0)) {
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
@@ -5830,7 +5923,7 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
+static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) {
// Ignore dependent types.
if (MD->isDependentContext())
return false;
@@ -5893,7 +5986,7 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
// We will need to mark all of the virtual members as referenced to build the
// vtable.
- if (!needsVtable(MD, Context))
+ if (!needsVTable(MD, Context))
return;
TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
@@ -5944,3 +6037,44 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
MarkVirtualMembersReferenced(Loc, Base);
}
}
+
+/// SetIvarInitializers - This routine builds initialization ASTs for the
+/// Objective-C implementation whose ivars need be initialized.
+void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
+ if (!getLangOptions().CPlusPlus)
+ return;
+ if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) {
+ llvm::SmallVector<ObjCIvarDecl*, 8> ivars;
+ CollectIvarsToConstructOrDestruct(OID, ivars);
+ if (ivars.empty())
+ return;
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
+ for (unsigned i = 0; i < ivars.size(); i++) {
+ FieldDecl *Field = ivars[i];
+ CXXBaseOrMemberInitializer *Member;
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDefault(ObjCImplementation->getLocation());
+
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(*this, InitEntity, InitKind,
+ Sema::MultiExprArg(*this, 0, 0));
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ // Note, MemberInit could actually come back empty if no initialization
+ // is required (e.g., because it would call a trivial default constructor)
+ if (!MemberInit.get() || MemberInit.isInvalid())
+ continue;
+
+ Member =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Field, SourceLocation(),
+ SourceLocation(),
+ MemberInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ ObjCImplementation->setIvarInitializers(Context,
+ AllToInit.data(), AllToInit.size());
+ }
+}