From: Sebastian Redl Date: Sun, 12 Feb 2012 18:41:05 +0000 (+0000) Subject: Proper initializer list support for new expressions and type construct expressions... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6dc00f6e98a00bd1c332927c3e04918d7e8b0d4f;p=clang Proper initializer list support for new expressions and type construct expressions. Array new still missing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150346 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index c35968cdb0..dbc8aa2eca 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 ">; 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>; // C++11 override control def override_keyword_only_allowed_on_virtual_member_functions : Error< diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 7dee5ecc5a..fe212f4ebc 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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); diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index c74bb9a067..e09da9db74 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -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(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(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(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(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c16d7e2282..c29f8c90aa 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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(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,21 +986,25 @@ 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(); AllocTypeInfo = DeducedType; AllocType = AllocTypeInfo->getType(); } - + // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. if (!ArraySize) { @@ -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(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,9 +1215,12 @@ 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(), - ConstructorLParen, - ConstructorRParen); + : ListInitialization ? InitializationKind::CreateDirectList( + TypeRange.getBegin()) + : InitializationKind::CreateDirect( + TypeRange.getBegin(), + ConstructorLParen, + ConstructorRParen); InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp index b716d81834..e4551d9891 100644 --- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp +++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp @@ -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*); }; diff --git a/test/SemaCXX/cxx0x-initializer-scalars.cpp b/test/SemaCXX/cxx0x-initializer-scalars.cpp index 7d2b5b3ab9..49f53b6057 100644 --- a/test/SemaCXX/cxx0x-initializer-scalars.cpp +++ b/test/SemaCXX/cxx0x-initializer-scalars.cpp @@ -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}} } } diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index fe3cd8fc3a..bfe3f7991e 100644 --- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -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{1, 2, 3}; // expected-warning {{at the end of the full-expression}} +} diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 13456e0c8d..f162c6f32d 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -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}} }