]> granicus.if.org Git - clang/commitdiff
Proper initializer list support for new expressions and type construct expressions...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 12 Feb 2012 18:41:05 +0000 (18:41 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 12 Feb 2012 18:41:05 +0000 (18:41 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150346 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaCast.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/cxx0x-initializer-aggregates.cpp
test/SemaCXX/cxx0x-initializer-scalars.cpp
test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
test/SemaCXX/cxx98-compat.cpp

index c35968cdb0d15006f30f44c5263c32021c4aba26..dbc8aa2ecad1d4409a315e7675e8d39254f6a0eb 100644 (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<
index 7dee5ecc5a81d635830ab6244a301e6b8d23e8e0..fe212f4ebcf68555300a7c1a109cf038d31fba0a 100644 (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);
 
index c74bb9a067d39757923565a900dbb38c64ae66d3..e09da9db7404001662fe5fa0a63c11c5c229443b 100644 (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();
 
index c16d7e2282ed0951f3bc20cdeab2642d78fa92d1..c29f8c90aac11d14cf297847db1705516b018581 100644 (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,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<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,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);
index b716d81834fd134393cb9095c3051efc2625c9cf..e4551d98914a424d98e282c87784fd2176691368 100644 (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*);
   };
index 7d2b5b3ab9f51d30ca1886d8422f0d6ade642388..49f53b60572b3155aa2424512c092c0c28a999ac 100644 (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}}
   }
 }
index fe3cd8fc3a13c4f2a369f7f4d7f476f2aabf1984..bfe3f7991eaae137d69af542e7148c88a4433299 100644 (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}}
+}
index 13456e0c8d25af003b132c39ea36aaf8bedb4c4a..f162c6f32d7b56924cbf55382932f59382e4d6ba 100644 (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}}
 }