Switch the C++ new expression over to InitializationSequence, rather
than using its own partial implementation of initialization.
Switched CheckInitializerTypes over to
InitializedEntity/InitializationKind, to help move us closer to
InitializationSequence.
Added InitializedEntity::getName() to retrieve the name of the entity,
for diagnostics that care about such things.
Implemented support for default initialization in
InitializationSequence.
Clean up the determination of the "source expressions" for an
initialization sequence in InitializationSequence::Perform.
Taught CXXConstructExpr to store more location information.
llvm-svn: 91492
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 32a5726..0472d50e 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -3676,8 +3676,8 @@
/// type checking declaration initializers (C99 6.7.8)
bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
- SourceLocation InitLoc,DeclarationName InitEntity,
- bool DirectInit);
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind);
bool CheckInitList(InitListExpr *&InitList, QualType &DeclType);
bool CheckForConstantInitializer(Expr *e, QualType t);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6c5c259..7a27e11 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3504,6 +3504,18 @@
Expr *Init = init.takeAs<Expr>();
assert(Init && "missing initializer");
+ // Capture the variable that is being initialized and the style of
+ // initialization.
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
+
+ // FIXME: Poor source location information.
+ InitializationKind Kind
+ = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(),
+ Init->getLocStart(),
+ Init->getLocEnd())
+ : InitializationKind::CreateCopy(VDecl->getLocation(),
+ Init->getLocStart());
+
// Get the decls type and save a reference for later, since
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
@@ -3514,16 +3526,6 @@
} else if (!VDecl->isInvalidDecl()) {
if (VDecl->getType()->isReferenceType()
|| isa<InitListExpr>(Init)) {
- InitializedEntity Entity
- = InitializedEntity::InitializeVariable(VDecl);
-
- // FIXME: Poor source location information.
- InitializationKind Kind
- = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(),
- SourceLocation(),
- SourceLocation())
- : InitializationKind::CreateCopy(VDecl->getLocation(),
- SourceLocation());
InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
if (InitSeq) {
OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
@@ -3540,8 +3542,7 @@
VDecl->setInvalidDecl();
return;
}
- } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName(), DirectInit))
+ } else if (CheckInitializerTypes(Init, DclT, Entity, Kind))
VDecl->setInvalidDecl();
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
@@ -3602,8 +3603,7 @@
if (VDecl->getStorageClass() == VarDecl::Extern)
Diag(VDecl->getLocation(), diag::warn_extern_init);
if (!VDecl->isInvalidDecl())
- if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName(), DirectInit))
+ if (CheckInitializerTypes(Init, DclT, Entity, Kind))
VDecl->setInvalidDecl();
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 80d67ef..a70841f 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -125,8 +125,10 @@
// the same semantic constraints as the initializer expression in
// a declaration of a variable of the parameter type, using the
// copy-initialization semantics (8.5).
- if (CheckInitializerTypes(Arg, ParamType, EqualLoc,
- Param->getDeclName(), /*DirectInit=*/false))
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Param);
+ InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(),
+ EqualLoc);
+ if (CheckInitializerTypes(Arg, ParamType, Entity, Kind))
return true;
Arg = MaybeCreateCXXExprWithTemporaries(Arg);
@@ -3775,7 +3777,8 @@
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
- return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor,
+ return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
+ Constructor,
Elidable, Exprs, NumExprs));
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 12c3a3a..70646dd 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -3531,8 +3532,12 @@
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
- //FIXME: Preserve type source info.
- QualType literalType = GetTypeFromParser(Ty);
+
+ TypeSourceInfo *TInfo = 0;
+ QualType literalType = GetTypeFromParser(Ty, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(literalType, LParenLoc);
+
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
@@ -3548,8 +3553,12 @@
literalExpr->getSourceRange().getEnd())))
return ExprError();
- if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
- DeclarationName(), /*FIXME:DirectInit=*/false))
+ InitializedEntity Entity
+ = InitializedEntity::InitializeTemporary(TInfo->getTypeLoc());
+ InitializationKind Kind
+ = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
+ /*IsCStyleCast=*/true);
+ if (CheckInitializerTypes(literalExpr, literalType, Entity, Kind))
return ExprError();
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
@@ -3558,6 +3567,8 @@
return ExprError();
}
InitExpr.release();
+
+ // FIXME: Store the TInfo to preserve type information better.
return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType,
literalExpr, isFileScope));
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index d119350..80b6430 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -425,74 +425,70 @@
bool Init = ConstructorLParen.isValid();
// --- Choosing a constructor ---
- // C++ 5.3.4p15
- // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid)
- // the object is not initialized. If the object, or any part of it, is
- // const-qualified, it's an error.
- // 2) If T is a POD and there's an empty initializer, the object is value-
- // initialized.
- // 3) If T is a POD and there's one initializer argument, the object is copy-
- // constructed.
- // 4) If T is a POD and there's more initializer arguments, it's an error.
- // 5) If T is not a POD, the initializer arguments are used as constructor
- // arguments.
- //
- // Or by the C++0x formulation:
- // 1) If there's no initializer, the object is default-initialized according
- // to C++0x rules.
- // 2) Otherwise, the object is direct-initialized.
CXXConstructorDecl *Constructor = 0;
Expr **ConsArgs = (Expr**)ConstructorArgs.get();
- const RecordType *RT;
unsigned NumConsArgs = ConstructorArgs.size();
ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
- if (AllocType->isDependentType() ||
- Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
- // Skip all the checks.
- } else if ((RT = AllocType->getAs<RecordType>()) &&
- !AllocType->isAggregateType()) {
- InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc);
- if (NumConsArgs > 0)
- InitKind = InitializationKind::CreateDirect(TypeLoc,
- PlacementLParen,
- PlacementRParen);
- Constructor = PerformInitializationByConstructor(
- AllocType, move(ConstructorArgs),
- TypeLoc,
- SourceRange(TypeLoc, ConstructorRParen),
- RT->getDecl()->getDeclName(),
- InitKind,
- ConvertedConstructorArgs);
- if (!Constructor)
+ if (!AllocType->isDependentType() &&
+ !Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
+ // C++0x [expr.new]p15:
+ // A new-expression that creates an object of type T initializes that
+ // object as follows:
+ InitializationKind Kind
+ // - If the new-initializer is omitted, the object is default-
+ // initialized (8.5); if no initialization is performed,
+ // the object has indeterminate value
+ = !Init? InitializationKind::CreateDefault(TypeLoc)
+ // - Otherwise, the new-initializer is interpreted according to the
+ // initialization rules of 8.5 for direct-initialization.
+ : InitializationKind::CreateDirect(TypeLoc,
+ ConstructorLParen,
+ ConstructorRParen);
+
+ // FIXME: We shouldn't have to fake this.
+ TypeSourceInfo *TInfo
+ = Context.getTrivialTypeSourceInfo(AllocType, TypeLoc);
+ InitializedEntity Entity
+ = InitializedEntity::InitializeTemporary(TInfo->getTypeLoc());
+ InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs);
+
+ if (!InitSeq) {
+ InitSeq.Diagnose(*this, Entity, Kind, ConsArgs, NumConsArgs);
return ExprError();
+ }
- // Take the converted constructor arguments and use them for the new
- // expression.
+ OwningExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
+ move(ConstructorArgs));
+ if (FullInit.isInvalid())
+ return ExprError();
+
+ // FullInit is our initializer; walk through it to determine if it's a
+ // constructor call, which CXXNewExpr handles directly.
+ if (Expr *FullInitExpr = (Expr *)FullInit.get()) {
+ if (CXXBindTemporaryExpr *Binder
+ = dyn_cast<CXXBindTemporaryExpr>(FullInitExpr))
+ FullInitExpr = Binder->getSubExpr();
+ if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(FullInitExpr)) {
+ Constructor = Construct->getConstructor();
+ for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(),
+ AEnd = Construct->arg_end();
+ A != AEnd; ++A)
+ ConvertedConstructorArgs.push_back(A->Retain());
+ } else {
+ // Take the converted initializer.
+ ConvertedConstructorArgs.push_back(FullInit.release());
+ }
+ } else {
+ // No initialization required.
+ }
+
+ // Take the converted arguments and use them for the new expression.
NumConsArgs = ConvertedConstructorArgs.size();
ConsArgs = (Expr **)ConvertedConstructorArgs.take();
- } else {
- if (!Init) {
- // FIXME: Check that no subpart is const.
- if (AllocType.isConstQualified())
- return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const)
- << TypeRange);
- } else if (NumConsArgs == 0) {
- // Object is value-initialized. Do nothing.
- } else if (NumConsArgs == 1) {
- // Object is direct-initialized.
- // FIXME: What DeclarationName do we pass in here?
- if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
- DeclarationName() /*AllocType.getAsString()*/,
- /*DirectInit=*/true))
- return ExprError();
- } else {
- return ExprError(Diag(StartLoc,
- diag::err_builtin_direct_init_more_than_one_arg)
- << SourceRange(ConstructorLParen, ConstructorRParen));
- }
}
-
+
// FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
PlacementArgs.release();
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 4518465..a732b07 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -135,8 +135,12 @@
}
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
- SourceLocation InitLoc,
- DeclarationName InitEntity, bool DirectInit) {
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind) {
+ SourceLocation InitLoc = Kind.getLocation();
+ DeclarationName InitEntity = Entity.getName();
+ bool DirectInit = (Kind.getKind() == InitializationKind::IK_Direct);
+
if (DeclType->isDependentType() ||
Init->isTypeDependent() || Init->isValueDependent()) {
// We have either a dependent type or a type- or value-dependent
@@ -1954,6 +1958,24 @@
return Result;
}
+DeclarationName InitializedEntity::getName() const {
+ switch (getKind()) {
+ case EK_Variable:
+ case EK_Parameter:
+ case EK_Member:
+ return VariableOrMember->getDeclName();
+
+ case EK_Result:
+ case EK_Exception:
+ case EK_Temporary:
+ case EK_Base:
+ return DeclarationName();
+ }
+
+ // Silence GCC warning
+ return DeclarationName();
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -2512,7 +2534,7 @@
Constructor = cast<CXXConstructorDecl>(*Con);
if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ (AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
@@ -2575,6 +2597,41 @@
Sequence.setSequenceKind(InitializationSequence::ZeroInitialization);
}
+/// \brief Attempt default initialization (C++ [dcl.init]p6).
+static void TryDefaultInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitializationSequence &Sequence) {
+ assert(Kind.getKind() == InitializationKind::IK_Default);
+
+ // C++ [dcl.init]p6:
+ // To default-initialize an object of type T means:
+ // - if T is an array type, each element is default-initialized;
+ QualType DestType = Entity.getType().getType();
+ while (const ArrayType *Array = S.Context.getAsArrayType(DestType))
+ DestType = Array->getElementType();
+
+ // - if T is a (possibly cv-qualified) class type (Clause 9), the default
+ // constructor for T is called (and the initialization is ill-formed if
+ // T has no accessible default constructor);
+ if (DestType->isRecordType()) {
+ // FIXME: If a program calls for the default initialization of an object of
+ // a const-qualified type T, T shall be a class type with a user-provided
+ // default constructor.
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType,
+ Sequence);
+ }
+
+ // - otherwise, no initialization is performed.
+ Sequence.setSequenceKind(InitializationSequence::NoInitialization);
+
+ // If a program calls for the default initialization of an object of
+ // a const-qualified type T, T shall be a class type with a user-provided
+ // default constructor.
+ if (DestType.isConstQualified())
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+}
+
/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
@@ -2749,7 +2806,7 @@
QualType SourceType;
Expr *Initializer = 0;
- if (Kind.getKind() == InitializationKind::IK_Copy) {
+ if (NumArgs == 1) {
Initializer = Args[0];
if (!isa<InitListExpr>(Initializer))
SourceType = Initializer->getType();
@@ -2785,11 +2842,18 @@
}
// - If the initializer is (), the object is value-initialized.
- if (Kind.getKind() == InitializationKind::IK_Value) {
+ if (Kind.getKind() == InitializationKind::IK_Value ||
+ (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) {
TryValueInitialization(S, Entity, Kind, *this);
return;
}
+ // Handle default initialization.
+ if (Kind.getKind() == InitializationKind::IK_Default){
+ TryDefaultInitialization(S, Entity, Kind, *this);
+ return;
+ }
+
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
if (const ArrayType *AT = Context.getAsArrayType(DestType)) {
@@ -2824,9 +2888,15 @@
return;
}
+ if (NumArgs > 1) {
+ SetFailed(FK_TooManyInitsForScalar);
+ return;
+ }
+ assert(NumArgs == 1 && "Zero-argument case handled above");
+
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
- if (SourceType->isRecordType()) {
+ if (!SourceType.isNull() && SourceType->isRecordType()) {
TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
return;
}
@@ -2836,6 +2906,7 @@
// conversions (Clause 4) will be used, if necessary, to convert the
// initializer expression to the cv-unqualified version of the
// destination type; no user-defined conversions are considered.
+ setSequenceKind(StandardConversion);
TryImplicitConversion(S, Entity, Kind, Initializer, *this);
}
@@ -2909,23 +2980,41 @@
SourceLocation()));
}
+ if (SequenceKind == NoInitialization)
+ return S.Owned((Expr *)0);
+
QualType DestType = Entity.getType().getType().getNonReferenceType();
if (ResultType)
*ResultType = Entity.getType().getType();
- Sema::OwningExprResult CurInit(S);
- // For copy initialization and any other initialization forms that
- // only have a single initializer, we start with the (only)
- // initializer we have.
- // FIXME: DPG is not happy about this. There's confusion regarding whether
- // we're supposed to start the conversion from the solitary initializer or
- // from the set of arguments.
- if (Kind.getKind() == InitializationKind::IK_Copy ||
- SequenceKind != ConstructorInitialization) {
- assert(Args.size() == 1);
- CurInit = Sema::OwningExprResult(S, Args.release()[0]);
- if (CurInit.isInvalid())
- return S.ExprError();
+ Sema::OwningExprResult CurInit = S.Owned((Expr *)0);
+
+ assert(!Steps.empty() && "Cannot have an empty initialization sequence");
+
+ // For initialization steps that start with a single initializer,
+ // grab the only argument out the Args and place it into the "current"
+ // initializer.
+ switch (Steps.front().Kind) {
+ case SK_ResolveAddressOfOverloadedFunction:
+ case SK_CastDerivedToBaseRValue:
+ case SK_CastDerivedToBaseLValue:
+ case SK_BindReference:
+ case SK_BindReferenceToTemporary:
+ case SK_UserConversion:
+ case SK_QualificationConversionLValue:
+ case SK_QualificationConversionRValue:
+ case SK_ConversionSequence:
+ case SK_ListInitialization:
+ assert(Args.size() == 1);
+ CurInit = Sema::OwningExprResult(S,
+ ((Expr **)(Args.get()))[0]->Retain());
+ if (CurInit.isInvalid())
+ return S.ExprError();
+ break;
+
+ case SK_ConstructorInitialization:
+ case SK_ZeroInitialization:
+ break;
}
// Walk through the computed steps for the initialization sequence,
@@ -2936,7 +3025,7 @@
return S.ExprError();
Expr *CurInitExpr = (Expr *)CurInit.get();
- QualType SourceType = CurInitExpr->getType();
+ QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType();
switch (Step->Kind) {
case SK_ResolveAddressOfOverloadedFunction:
@@ -3100,7 +3189,6 @@
if (CurInit.isInvalid())
return S.ExprError();
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
break;
}
@@ -3228,12 +3316,16 @@
break;
case FK_TooManyInitsForScalar: {
- InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ SourceRange R;
+
+ if (InitListExpr *InitList = dyn_cast<InitListExpr>(Args[0]))
+ R = SourceRange(InitList->getInit(1)->getLocStart(),
+ InitList->getLocEnd());
+ else
+ R = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
- << /*scalar=*/2
- << SourceRange(InitList->getInit(1)->getLocStart(),
- InitList->getLocEnd());
+ << /*scalar=*/2 << R;
break;
}
@@ -3290,6 +3382,11 @@
}
break;
}
+
+ case FK_DefaultInitOfConst:
+ S.Diag(Kind.getLocation(), diag::err_default_init_const)
+ << DestType;
+ break;
}
return true;
diff --git a/clang/lib/Sema/SemaInit.h b/clang/lib/Sema/SemaInit.h
index 2d4b01f..c084025 100644
--- a/clang/lib/Sema/SemaInit.h
+++ b/clang/lib/Sema/SemaInit.h
@@ -137,8 +137,8 @@
}
/// \brief Create the initialization entity for a temporary.
- static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) {
- return InitializedEntity(Kind, SourceLocation(), TL);
+ static InitializedEntity InitializeTemporary(TypeLoc TL) {
+ return InitializedEntity(EK_Temporary, SourceLocation(), TL);
}
/// \brief Create the initialization entity for a base class subobject.
@@ -156,6 +156,9 @@
/// \brief Retrieve type being initialized.
TypeLoc getType() const { return TL; }
+ /// \brief Retrieve the name of the entity being initialized.
+ DeclarationName getName() const;
+
/// \brief Determine the location of the 'return' keyword when initializing
/// the result of a function call.
SourceLocation getReturnLoc() const {
@@ -319,7 +322,13 @@
ListInitialization,
/// \brief Zero-initialization.
- ZeroInitialization
+ ZeroInitialization,
+
+ /// \brief No initialization required.
+ NoInitialization,
+
+ /// \brief Standard conversion sequence.
+ StandardConversion
};
/// \brief Describes the kind of a particular step in an initialization
@@ -420,7 +429,9 @@
/// \brief Overloading for a user-defined conversion failed.
FK_UserConversionOverloadFailed,
/// \brief Overloaded for initialization by constructor failed.
- FK_ConstructorOverloadFailed
+ FK_ConstructorOverloadFailed,
+ /// \brief Default-initialization of a 'const' object.
+ FK_DefaultInitOfConst
};
private: