Proper initializer list support for new expressions and type construct expressions. Array new still missing.

llvm-svn: 150346
This commit is contained in:
Sebastian Redl 2012-02-12 18:41:05 +00:00
parent 1a22d2889b
commit d74dd49065
8 changed files with 106 additions and 43 deletions

View File

@ -1232,6 +1232,8 @@ def err_auto_var_requires_init : Error<
"declaration of variable %0 with type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
"new expression for type %0 requires a constructor argument">;
def err_auto_new_requires_parens : Error<
"new expression for type %0 cannot use list-initialization">;
def err_auto_var_init_no_expression : Error<
"initializer for variable %0 with type %1 is empty">;
def err_auto_var_init_multiple_expressions : Error<
@ -1257,6 +1259,10 @@ def err_implied_std_initializer_list_not_found : Error<
"not found; include <initializer_list>">;
def err_malformed_std_initializer_list : Error<
"std::initializer_list must be a class template with a single type parameter">;
def warn_dangling_std_initializer_list : Warning<
"array backing the initializer list will be destroyed at the end of "
"%select{the full-expression|the constructor}0">,
InGroup<DiagGroup<"dangling-initializer-list">>;
// C++11 override control
def override_keyword_only_allowed_on_virtual_member_functions : Error<

View File

@ -1151,10 +1151,13 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
&& "Expected '(' or '{'!");
if (Tok.is(tok::l_brace)) {
// FIXME: Convert to a proper type construct expression.
return ParseBraceInitializer();
ExprResult Init = ParseBraceInitializer();
if (Init.isInvalid())
return Init;
Expr *InitList = Init.take();
return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(),
MultiExprArg(&InitList, 1),
SourceLocation());
} else {
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);

View File

@ -77,7 +77,7 @@ namespace {
void CheckReinterpretCast();
void CheckStaticCast();
void CheckDynamicCast();
void CheckCXXCStyleCast(bool FunctionalCast);
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
/// Complete an apparently-successful cast operation that yields
@ -190,15 +190,15 @@ static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
unsigned &msg, CastKind &Kind,
bool ListInitialization);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath);
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath,
bool ListInitialization);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
@ -752,7 +752,7 @@ void CastOperation::CheckStaticCast() {
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr
= TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
Kind, BasePath);
Kind, BasePath, /*ListInitialization=*/false);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
@ -782,8 +782,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath) {
CastKind &Kind, CXXCastPath &BasePath,
bool ListInitialization) {
// Determine whether we have the semantics of a C-style cast.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
@ -808,23 +808,23 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.9p5, reference downcast.
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle, OpRange,
msg, Kind, BasePath);
tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle,
OpRange, msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
// C++0x [expr.static.cast]p3:
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2
// T2" if "cv2 T2" is reference-compatible with "cv1 T1".
tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, BasePath,
msg);
tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind,
BasePath, msg);
if (tcr != TC_NotApplicable)
return tcr;
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
Kind);
Kind, ListInitialization);
if (SrcExpr.isInvalid())
return TC_Failed;
if (tcr != TC_NotApplicable)
@ -1295,7 +1295,7 @@ TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind) {
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_dynamic_cast_incomplete)) {
@ -1304,15 +1304,13 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
}
// FIXME: doesn't correctly identify T({1})
bool InitList = isa<InitListExpr>(SrcExpr.get());
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= (CCK == Sema::CCK_CStyleCast)
? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange,
InitList)
ListInitialization)
: (CCK == Sema::CCK_FunctionalCast)
? InitializationKind::CreateFunctionalCast(OpRange, InitList)
? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
: InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
@ -1756,7 +1754,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_Success;
}
void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
bool ListInitialization) {
// Handle placeholders.
if (isPlaceholder()) {
// C-style casts can resolve __unknown_any types.
@ -1839,7 +1838,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange,
msg, Kind, BasePath);
msg, Kind, BasePath, ListInitialization);
if (SrcExpr.isInvalid())
return;
@ -2073,7 +2072,8 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd());
if (getLangOptions().CPlusPlus) {
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false);
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false,
isa<InitListExpr>(CastExpr));
} else {
Op.CheckCStyleCast();
}
@ -2090,11 +2090,14 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
SourceLocation LPLoc,
Expr *CastExpr,
SourceLocation RPLoc) {
bool ListInitialization = LPLoc.isInvalid();
assert((!ListInitialization || isa<InitListExpr>(CastExpr)) &&
"List initialization must have initializer list as expression.");
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true);
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true, ListInitialization);
if (Op.SrcExpr.isInvalid())
return ExprError();

View File

@ -767,7 +767,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc);
if (Ty->isDependentType() ||
CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
@ -779,6 +778,12 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
RParenLoc));
}
bool ListInitialization = LParenLoc.isInvalid();
assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0])))
&& "List initialization must have initializer list as expression.");
SourceRange FullRange = SourceRange(TyBeginLoc,
ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc);
if (Ty->isArrayType())
return ExprError(Diag(TyBeginLoc,
diag::err_value_init_for_array_type) << FullRange);
@ -872,11 +877,24 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
return (del->getNumParams() == 2);
}
/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.:
/// \brief Parsed a C++ 'new' expression (C++ 5.3.4).
/// E.g.:
/// @code new (memory) int[size][4] @endcode
/// or
/// @code ::new Foo(23, "hello") @endcode
/// For the interpretation of this heap of arguments, consult the base version.
///
/// \param StartLoc The first location of the expression.
/// \param UseGlobal True if 'new' was prefixed with '::'.
/// \param PlacementLParen Opening paren of the placement arguments.
/// \param PlacementArgs Placement new arguments.
/// \param PlacementRParen Closing paren of the placement arguments.
/// \param TypeIdParens If the type is in parens, the source range.
/// \param D The type to be allocated, as well as array dimensions.
/// \param ConstructorLParen Opening paren of the constructor args, empty if
/// initializer-list syntax is used.
/// \param ConstructorArgs Constructor/initialization arguments.
/// \param ConstructorRParen Closing paren of the constructor args.
ExprResult
Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
@ -968,14 +986,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
diag::err_auto_new_ctor_multiple_expressions)
<< AllocType << TypeRange);
}
Expr *Deduce = ConstructorArgs.get()[0];
if (ConstructorLParen.isInvalid()) {
return ExprError(Diag(Deduce->getSourceRange().getBegin(),
diag::err_auto_new_requires_parens)
<< AllocType << TypeRange);
}
TypeSourceInfo *DeducedType = 0;
if (DeduceAutoType(AllocTypeInfo, ConstructorArgs.get()[0], DeducedType) ==
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) ==
DAR_Failed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
<< AllocType
<< ConstructorArgs.get()[0]->getType()
<< TypeRange
<< ConstructorArgs.get()[0]->getSourceRange());
<< AllocType << Deduce->getType()
<< TypeRange << Deduce->getSourceRange());
if (!DeducedType)
return ExprError();
@ -998,6 +1020,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
bool ListInitialization = ConstructorLParen.isInvalid() &&
ConstructorArgs.size() > 0;
assert((!ListInitialization || (ConstructorArgs.size() == 1 &&
isa<InitListExpr>(ConstructorArgs.get()[0])))
&& "List initialization means a braced-init-list for arguments.");
if (ListInitialization && isStdInitializerList(AllocType, 0)) {
Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(),
diag::warn_dangling_std_initializer_list)
<< /*at end of FE*/0 << ConstructorArgs.get()[0]->getSourceRange();
}
// In ARC, infer 'retaining' for the allocated
if (getLangOptions().ObjCAutoRefCount &&
AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
@ -1153,7 +1186,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
bool Init = ConstructorLParen.isValid();
bool Init = ConstructorLParen.isValid() || ConstructorArgs.size() > 0;
// --- Choosing a constructor ---
CXXConstructorDecl *Constructor = 0;
bool HadMultipleCandidates = false;
@ -1172,7 +1205,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
// C++0x [expr.new]p15:
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
InitializationKind Kind
@ -1182,7 +1215,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
= !Init? InitializationKind::CreateDefault(TypeRange.getBegin())
// - Otherwise, the new-initializer is interpreted according to the
// initialization rules of 8.5 for direct-initialization.
: InitializationKind::CreateDirect(TypeRange.getBegin(),
: ListInitialization ? InitializationKind::CreateDirectList(
TypeRange.getBegin())
: InitializationKind::CreateDirect(
TypeRange.getBegin(),
ConstructorLParen,
ConstructorRParen);

View File

@ -27,6 +27,13 @@ namespace aggregate {
S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
}
void bracing_new() {
new S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
new S{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
new S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
new S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
}
struct String {
String(const char*);
};

View File

@ -25,7 +25,7 @@ namespace integral {
}
void inline_init() {
(void) int{1};
auto v = int{1};
(void) new int{1};
}
@ -59,5 +59,7 @@ namespace integral {
void edge_cases() {
// FIXME: very poor error message
int a({0}); // expected-error {{cannot initialize}}
(void) int({0}); // expected-error {{functional-style cast}}
new int({0}); // expected-error {{cannot initialize}}
}
}

View File

@ -122,3 +122,8 @@ void auto_deduction() {
for (int i : {1, 2, 3, 4}) {}
}
void dangle() {
new auto{1, 2, 3}; // expected-error {{cannot use list-initialization}}
new std::initializer_list<int>{1, 2, 3}; // expected-warning {{at the end of the full-expression}}
}

View File

@ -41,7 +41,8 @@ void Lambda() {
int InitList() {
(void)new int {}; // expected-warning {{generalized initializer lists are incompatible with C++98}} \
// expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
(void)int{}; // expected-warning {{generalized initializer lists are incompatible with C++98}}
(void)int{}; // expected-warning {{generalized initializer lists are incompatible with C++98}} \
// expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
int x { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
return { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
}