[cfe-commits] r145186 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Initialization.h lib/AST/ExprClassification.cpp lib/CodeGen/CGExpr.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaInit.cpp test/CodeGenCXX/cxx0x-initializer-references.cpp test/SemaCXX/cxx0x-initializer-references.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sun Nov 27 08:50:07 PST 2011


Author: cornedbee
Date: Sun Nov 27 10:50:07 2011
New Revision: 145186

URL: http://llvm.org/viewvc/llvm-project?rev=145186&view=rev
Log:
Reference initialization with initializer lists.

This supports single-element initializer lists for references according to DR1288, as well as creating temporaries and binding to them for other initializer lists.

Added:
    cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Nov 27 10:50:07 2011
@@ -1034,6 +1034,9 @@
 def err_not_reference_to_const_init : Error<
   "%select{non-const|volatile}0 lvalue reference to type %1 cannot be "
   "initialized with a %select{value|temporary}2 of type %3">;
+def err_lvalue_reference_bind_to_initlist : Error<
+  "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an "
+  "initializer list temporary">;
 def err_lvalue_reference_bind_to_temporary : Error<
   "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a "
   "temporary of type %2">;

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Sun Nov 27 10:50:07 2011
@@ -530,6 +530,10 @@
     SK_ListInitialization,
     /// \brief Perform list-initialization with a constructor.
     SK_ListConstructorCall,
+    /// \brief Unwrap the single-element initializer list for a reference.
+    SK_UnwrapInitList,
+    /// \brief Rewrap the single-element initializer list for a reference.
+    SK_RewrapInitList,
     /// \brief Perform initialization via a constructor.
     SK_ConstructorInitialization,
     /// \brief Zero-initialize the object
@@ -579,8 +583,12 @@
       } Function;
 
       /// \brief When Kind = SK_ConversionSequence, the implicit conversion
-      /// sequence 
+      /// sequence.
       ImplicitConversionSequence *ICS;
+
+      /// \brief When Kind = SK_RewrapInitList, the syntactic form of the
+      /// wrapping list.
+      InitListExpr *WrappingSyntacticList;
     };
 
     void Destroy();
@@ -853,6 +861,10 @@
   /// retaining it).
   void AddProduceObjCObjectStep(QualType T);
 
+  /// \brief Add steps to unwrap a initializer list for a reference around a
+  /// single element and rewrap it at the end.
+  void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
+
   /// \brief Note that this initialization sequence failed.
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Sun Nov 27 10:50:07 2011
@@ -93,7 +93,6 @@
   const LangOptions &Lang = Ctx.getLangOptions();
 
   switch (E->getStmtClass()) {
-    // First come the expressions that are always lvalues, unconditionally.
   case Stmt::NoStmtClass:
 #define ABSTRACT_STMT(Kind)
 #define STMT(Kind, Base) case Expr::Kind##Class:
@@ -101,6 +100,8 @@
 #include "clang/AST/StmtNodes.inc"
     llvm_unreachable("cannot classify a statement");
     break;
+
+    // First come the expressions that are always lvalues, unconditionally.
   case Expr::ObjCIsaExprClass:
     // C++ [expr.prim.general]p1: A string literal is an lvalue.
   case Expr::StringLiteralClass:
@@ -122,6 +123,7 @@
     // FIXME: ObjC++0x might have different rules
   case Expr::ObjCIvarRefExprClass:
     return Cl::CL_LValue;
+
     // C99 6.5.2.5p5 says that compound literals are lvalues.
     // In C++, they're class temporaries.
   case Expr::CompoundLiteralExprClass:
@@ -157,7 +159,6 @@
   case Expr::ObjCProtocolExprClass:
   case Expr::ObjCStringLiteralClass:
   case Expr::ParenListExprClass:
-  case Expr::InitListExprClass:
   case Expr::SizeOfPackExprClass:
   case Expr::SubstNonTypeTemplateParmPackExprClass:
   case Expr::AsTypeExprClass:
@@ -229,8 +230,7 @@
     }
 
   case Expr::OpaqueValueExprClass:
-    return ClassifyExprValueKind(Lang, E,
-                                 cast<OpaqueValueExpr>(E)->getValueKind());
+    return ClassifyExprValueKind(Lang, E, E->getValueKind());
 
     // Pseudo-object expressions can produce l-values with reference magic.
   case Expr::PseudoObjectExprClass:
@@ -240,8 +240,7 @@
     // Implicit casts are lvalues if they're lvalue casts. Other than that, we
     // only specifically record class temporaries.
   case Expr::ImplicitCastExprClass:
-    return ClassifyExprValueKind(Lang, E,
-                                 cast<ImplicitCastExpr>(E)->getValueKind());
+    return ClassifyExprValueKind(Lang, E, E->getValueKind());
 
     // C++ [expr.prim.general]p4: The presence of parentheses does not affect
     //   whether the expression is an lvalue.
@@ -337,29 +336,40 @@
 
   case Expr::VAArgExprClass:
     return ClassifyUnnamed(Ctx, E->getType());
-      
+
   case Expr::DesignatedInitExprClass:
     return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit());
-      
+
   case Expr::StmtExprClass: {
     const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt();
     if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back()))
       return ClassifyUnnamed(Ctx, LastExpr->getType());
     return Cl::CL_PRValue;
   }
-      
+
   case Expr::CXXUuidofExprClass:
     return Cl::CL_LValue;
-      
+
   case Expr::PackExpansionExprClass:
     return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
-      
+
   case Expr::MaterializeTemporaryExprClass:
     return cast<MaterializeTemporaryExpr>(E)->isBoundToLvalueReference()
               ? Cl::CL_LValue 
               : Cl::CL_XValue;
+
+  case Expr::InitListExprClass:
+    // An init list can be an lvalue if it is bound to a reference and
+    // contains only one element. In that case, we look at that element
+    // for an exact classification. Init list creation takes care of the
+    // value kind for us, so we only need to fine-tune.
+    if (E->isRValue())
+      return ClassifyExprValueKind(Lang, E, E->getValueKind());
+    assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
+           "Only 1-element init lists can be glvalues.");
+    return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
   }
-  
+
   llvm_unreachable("unhandled expression kind in classification");
   return Cl::CL_LValue;
 }

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Nov 27 10:50:07 2011
@@ -210,6 +210,13 @@
                             const CXXDestructorDecl *&ReferenceTemporaryDtor,
                             QualType &ObjCARCReferenceLifetimeType,
                             const NamedDecl *InitializedDecl) {
+  // Look through single-element init lists that claim to be lvalues. They're
+  // just syntactic wrappers in this case.
+  if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+    if (ILE->getNumInits() == 1 && ILE->isGLValue())
+      E = ILE->getInit(0);
+  }
+
   // Look through expressions for materialized temporaries (for now).
   if (const MaterializeTemporaryExpr *M 
                                       = dyn_cast<MaterializeTemporaryExpr>(E)) {
@@ -669,6 +676,10 @@
     return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
   case Expr::PseudoObjectExprClass:
     return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
+  case Expr::InitListExprClass:
+    assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
+           "Only single-element init list can be lvalue.");
+    return EmitLValue(cast<InitListExpr>(E)->getInit(0));
 
   case Expr::BlockDeclRefExprClass:
     return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
@@ -728,7 +739,7 @@
   case Expr::CXXConstCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
     return EmitCastLValue(cast<CastExpr>(E));
-      
+
   case Expr::MaterializeTemporaryExprClass:
     return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
   }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Nov 27 10:50:07 2011
@@ -6199,7 +6199,7 @@
   // "ary" transitions from a VariableArrayType to a ConstantArrayType.
   if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
     VDecl->setType(DclT);
-    Init->setType(DclT);
+    Init->setType(DclT.getNonReferenceType());
   }
   
   // Check any implicit conversions within the expression.

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Sun Nov 27 10:50:07 2011
@@ -989,8 +989,7 @@
   }
 
   Expr *expr = IList->getInit(Index);
-  if (isa<InitListExpr>(expr)) {
-    // FIXME: Allowed in C++11.
+  if (isa<InitListExpr>(expr) && !SemaRef.getLangOptions().CPlusPlus0x) {
     if (!VerifyOnly)
       SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
         << DeclType << IList->getSourceRange();
@@ -2385,6 +2384,8 @@
   case SK_QualificationConversionLValue:
   case SK_ListInitialization:
   case SK_ListConstructorCall:
+  case SK_UnwrapInitList:
+  case SK_RewrapInitList:
   case SK_ConstructorInitialization:
   case SK_ZeroInitialization:
   case SK_CAssignment:
@@ -2761,6 +2762,21 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::RewrapReferenceInitList(QualType T,
+                                                     InitListExpr *Syntactic) {
+  assert(Syntactic->getNumInits() == 1 &&
+         "Can only rewrap trivial init lists.");
+  Step S;
+  S.Kind = SK_UnwrapInitList;
+  S.Type = Syntactic->getInit(0)->getType();
+  Steps.insert(Steps.begin(), S);
+
+  S.Kind = SK_RewrapInitList;
+  S.Type = T;
+  S.WrappingSyntacticList = Syntactic;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::SetOverloadFailure(FailureKind Failure,
                                                 OverloadingResult Result) {
   setSequenceKind(FailedSequence);
@@ -2799,6 +2815,114 @@
   }
 }
 
+static bool
+ResolveOverloadedFunctionForReferenceBinding(Sema &S,
+                                             Expr *Initializer,
+                                             QualType &SourceType,
+                                             QualType &UnqualifiedSourceType,
+                                             QualType UnqualifiedTargetType,
+                                             InitializationSequence &Sequence) {
+  if (S.Context.getCanonicalType(UnqualifiedSourceType) ==
+        S.Context.OverloadTy) {
+    DeclAccessPair Found;
+    bool HadMultipleCandidates = false;
+    if (FunctionDecl *Fn
+        = S.ResolveAddressOfOverloadedFunction(Initializer,
+                                               UnqualifiedTargetType,
+                                               false, Found,
+                                               &HadMultipleCandidates)) {
+      Sequence.AddAddressOverloadResolutionStep(Fn, Found,
+                                                HadMultipleCandidates);
+      SourceType = Fn->getType();
+      UnqualifiedSourceType = SourceType.getUnqualifiedType();
+    } else if (!UnqualifiedTargetType->isRecordType()) {
+      Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
+      return true;
+    }
+  }
+  return false;
+}
+
+static void TryReferenceInitializationCore(Sema &S,
+                                           const InitializedEntity &Entity,
+                                           const InitializationKind &Kind,
+                                           Expr *Initializer,
+                                           QualType cv1T1, QualType T1,
+                                           Qualifiers T1Quals,
+                                           QualType cv2T2, QualType T2,
+                                           Qualifiers T2Quals,
+                                           InitializationSequence &Sequence);
+
+static void TryListInitialization(Sema &S,
+                                  const InitializedEntity &Entity,
+                                  const InitializationKind &Kind,
+                                  InitListExpr *InitList,
+                                  InitializationSequence &Sequence);
+
+/// \brief Attempt list initialization of a reference.
+static void TryReferenceListInitialization(Sema &S,
+                                           const InitializedEntity &Entity,
+                                           const InitializationKind &Kind,
+                                           InitListExpr *InitList,
+                                           InitializationSequence &Sequence)
+{
+  // First, catch C++03 where this isn't possible.
+  if (!S.getLangOptions().CPlusPlus0x) {
+    Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+    return;
+  }
+
+  QualType DestType = Entity.getType();
+  QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+  Qualifiers T1Quals;
+  QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
+
+  // Reference initialization via an initializer list works thus:
+  // If the initializer list consists of a single element that is
+  // reference-related to the referenced type, bind directly to that element
+  // (possibly creating temporaries).
+  // Otherwise, initialize a temporary with the initializer list and
+  // bind to that.
+  if (InitList->getNumInits() == 1) {
+    Expr *Initializer = InitList->getInit(0);
+    QualType cv2T2 = Initializer->getType();
+    Qualifiers T2Quals;
+    QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
+
+    // If this fails, creating a temporary wouldn't work either.
+    if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
+                                                     T1, Sequence))
+      return;
+
+    SourceLocation DeclLoc = Initializer->getLocStart();
+    bool dummy1, dummy2, dummy3;
+    Sema::ReferenceCompareResult RefRelationship
+      = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
+                                       dummy2, dummy3);
+    if (RefRelationship >= Sema::Ref_Related) {
+      // Try to bind the reference here.
+      TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
+                                     T1Quals, cv2T2, T2, T2Quals, Sequence);
+      if (Sequence)
+        Sequence.RewrapReferenceInitList(cv1T1, InitList);
+      return;
+    }
+  }
+
+  // Not reference-related. Create a temporary and bind to that.
+  InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
+
+  TryListInitialization(S, TempEntity, Kind, InitList, Sequence);
+  if (Sequence) {
+    if (DestType->isRValueReferenceType() ||
+        (T1Quals.hasConst() && !T1Quals.hasVolatile()))
+      Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+    else
+      Sequence.SetFailed(
+          InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+  }
+}
+
 /// \brief Attempt list initialization (C++0x [dcl.init.list])
 static void TryListInitialization(Sema &S,
                                   const InitializedEntity &Entity,
@@ -2814,11 +2938,11 @@
     Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
     return;
   }
-  // FIXME: C++0x defines behavior for these two cases.
   if (DestType->isReferenceType()) {
-    Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+    TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);
     return;
   }
+  // FIXME: C++11 defines behavior for this case.
   if (DestType->isRecordType() && !DestType->isAggregateType()) {
     Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
     return;
@@ -3041,27 +3165,31 @@
   QualType cv2T2 = Initializer->getType();
   Qualifiers T2Quals;
   QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
-  SourceLocation DeclLoc = Initializer->getLocStart();
 
   // 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 (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
-    DeclAccessPair Found;
-    bool HadMultipleCandidates = false;
-    if (FunctionDecl *Fn
-        = S.ResolveAddressOfOverloadedFunction(Initializer, T1, false, Found,
-                                               &HadMultipleCandidates)) {
-      Sequence.AddAddressOverloadResolutionStep(Fn, Found,
-                                                HadMultipleCandidates);
-      cv2T2 = Fn->getType();
-      T2 = cv2T2.getUnqualifiedType();
-    } else if (!T1->isRecordType()) {
-      Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
-      return;
-    }
-  }
+  if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
+                                                   T1, Sequence))
+    return;
+
+  // Delegate everything else to a subfunction.
+  TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
+                                 T1Quals, cv2T2, T2, T2Quals, Sequence);
+}
 
+/// \brief Reference initialization without resolving overloaded functions.
+static void TryReferenceInitializationCore(Sema &S,
+                                           const InitializedEntity &Entity,
+                                           const InitializationKind &Kind,
+                                           Expr *Initializer,
+                                           QualType cv1T1, QualType T1,
+                                           Qualifiers T1Quals,
+                                           QualType cv2T2, QualType T2,
+                                           Qualifiers T2Quals,
+                                           InitializationSequence &Sequence) {
+  QualType DestType = Entity.getType();
+  SourceLocation DeclLoc = Initializer->getLocStart();
   // Compute some basic properties of the types and the initializer.
   bool isLValueRef = DestType->isLValueReferenceType();
   bool isRValueRef = !isLValueRef;
@@ -4486,6 +4614,8 @@
   case SK_ConversionSequence:
   case SK_ListConstructorCall:
   case SK_ListInitialization:
+  case SK_UnwrapInitList:
+  case SK_RewrapInitList:
   case SK_CAssignment:
   case SK_StringInit:
   case SK_ObjCObjectConversion:
@@ -4746,22 +4876,59 @@
 
     case SK_ListInitialization: {
       InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
-      QualType Ty = Step->Type;
-      InitListChecker PerformInitList(S, Entity, InitList,
-          ResultType ? *ResultType : Ty, /*VerifyOnly=*/false,
+      // Hack: We must pass *ResultType if available in order to set the type
+      // of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
+      // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a
+      // temporary, not a reference, so we should pass Ty.
+      // Worst case: 'const int (&arref)[] = {1, 2, 3};'.
+      // Since this step is never used for a reference directly, we explicitly
+      // unwrap references here and rewrap them afterwards.
+      // We also need to create a InitializeTemporary entity for this.
+      QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type;
+      bool IsTemporary = ResultType && (*ResultType)->isReferenceType();
+      InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
+      InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity,
+          InitList, Ty, /*VerifyOnly=*/false,
           Kind.getKind() != InitializationKind::IK_Direct ||
             !S.getLangOptions().CPlusPlus0x);
       if (PerformInitList.HadError())
         return ExprError();
 
+      if (ResultType) {
+        if ((*ResultType)->isRValueReferenceType())
+          Ty = S.Context.getRValueReferenceType(Ty);
+        else if ((*ResultType)->isLValueReferenceType())
+          Ty = S.Context.getLValueReferenceType(Ty,
+            (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue());
+        *ResultType = Ty;
+      }
+
+      InitListExpr *StructuredInitList =
+          PerformInitList.getFullyStructuredList();
       CurInit.release();
-      CurInit = S.Owned(PerformInitList.getFullyStructuredList());
+      CurInit = S.Owned(StructuredInitList);
       break;
     }
 
     case SK_ListConstructorCall:
       assert(false && "List constructor calls not yet supported.");
 
+    case SK_UnwrapInitList:
+      CurInit = S.Owned(cast<InitListExpr>(CurInit.take())->getInit(0));
+      break;
+
+    case SK_RewrapInitList: {
+      Expr *E = CurInit.take();
+      InitListExpr *Syntactic = Step->WrappingSyntacticList;
+      InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
+          Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc());
+      ILE->setSyntacticForm(Syntactic);
+      ILE->setType(E->getType());
+      ILE->setValueKind(E->getValueKind());
+      CurInit = S.Owned(ILE);
+      break;
+    }
+
     case SK_ConstructorInitialization: {
       unsigned NumArgs = Args.size();
       CXXConstructorDecl *Constructor
@@ -5081,6 +5248,16 @@
     break;
 
   case FK_NonConstLValueReferenceBindingToTemporary:
+    if (isa<InitListExpr>(Args[0])) {
+      S.Diag(Kind.getLocation(),
+             diag::err_lvalue_reference_bind_to_initlist)
+      << DestType.getNonReferenceType().isVolatileQualified()
+      << DestType.getNonReferenceType()
+      << Args[0]->getSourceRange();
+      break;
+    }
+    // Intentional fallthrough
+
   case FK_NonConstLValueReferenceBindingToUnrelated:
     S.Diag(Kind.getLocation(),
            Failure == FK_NonConstLValueReferenceBindingToTemporary
@@ -5446,9 +5623,11 @@
 
     case SK_QualificationConversionRValue:
       OS << "qualification conversion (rvalue)";
+      break;
 
     case SK_QualificationConversionXValue:
       OS << "qualification conversion (xvalue)";
+      break;
 
     case SK_QualificationConversionLValue:
       OS << "qualification conversion (lvalue)";
@@ -5468,6 +5647,14 @@
       OS << "list initialization via constructor";
       break;
 
+    case SK_UnwrapInitList:
+      OS << "unwrap reference initializer list";
+      break;
+
+    case SK_RewrapInitList:
+      OS << "rewrap reference initializer list";
+      break;
+
     case SK_ConstructorInitialization:
       OS << "constructor initialization";
       break;

Added: cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp?rev=145186&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp Sun Nov 27 10:50:07 2011
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+namespace reference {
+  struct A {
+    int i1, i2;
+  };
+
+  void single_init() {
+    // No superfluous instructions allowed here, they could be
+    // hiding extra temporaries.
+
+    // CHECK: store i32 1, i32*
+    // CHECK-NEXT: store i32* %{{.*}}, i32**
+    const int &cri2a = 1;
+
+    // CHECK-NEXT: store i32 1, i32*
+    // CHECK-NEXT: store i32* %{{.*}}, i32**
+    const int &cri1a = {1};
+
+    // CHECK-NEXT: store i32 1, i32*
+    int i = 1;
+    // CHECK-NEXT: store i32* %{{.*}}, i32**
+    int &ri1a = {i};
+
+    // CHECK-NEXT: bitcast
+    // CHECK-NEXT: memcpy
+    A a{1, 2};
+    // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
+    A &ra1a = {a};
+
+    // CHECK-NEXT: ret
+  }
+
+  void reference_to_aggregate() {
+    // CHECK: getelementptr {{.*}}, i32 0, i32 0
+    // CHECK-NEXT: store i32 1
+    // CHECK-NEXT: getelementptr {{.*}}, i32 0, i32 1
+    // CHECK-NEXT: store i32 2
+    // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align
+    const A &ra1{1, 2};
+
+    // CHECK-NEXT: getelementptr inbounds [3 x i32]* %{{.*}}, i{{32|64}} 0, i{{32|64}} 0
+    // CHECK-NEXT: store i32 1
+    // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1
+    // CHECK-NEXT: store i32 2
+    // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1
+    // CHECK-NEXT: store i32 3
+    // CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align
+    const int (&arrayRef)[] = {1, 2, 3};
+
+    // CHECK-NEXT: ret
+  }
+
+  struct B {
+    B();
+    ~B();
+  };
+
+  void single_init_temp_cleanup()
+  {
+    // Ensure lifetime extension.
+
+    // CHECK: call void @_ZN9reference1BC1Ev
+    // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
+    const B &rb{ B() };
+    // CHECK: call void @_ZN9reference1BD1Ev
+  }
+
+}

Added: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=145186&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Sun Nov 27 10:50:07 2011
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace reference {
+  struct A {
+    int i1, i2;
+  };
+
+  void single_init() {
+    const int &cri1a = {1};
+    const int &cri1b{1};
+
+    int i = 1;
+    int &ri1a = {i};
+    int &ri1b{i};
+
+    int &ri2 = {1}; // expected-error {{cannot bind to an initializer list temporary}}
+
+    A a{1, 2};
+    A &ra1a = {a};
+    A &ra1b{a};
+  }
+
+  void reference_to_aggregate() {
+    const A &ra1{1, 2};
+    A &ra2{1, 2}; // expected-error {{cannot bind to an initializer list temporary}}
+
+    const int (&arrayRef)[] = {1, 2, 3};
+    static_assert(sizeof(arrayRef) == 3 * sizeof(int), "bad array size");
+  }
+
+}





More information about the cfe-commits mailing list