r289250 - DR1295 and cleanup for P0135R1: Make our initialization code more directly

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 9 10:49:14 PST 2016


Author: rsmith
Date: Fri Dec  9 12:49:13 2016
New Revision: 289250

URL: http://llvm.org/viewvc/llvm-project?rev=289250&view=rev
Log:
DR1295 and cleanup for P0135R1: Make our initialization code more directly
mirror the description in the standard. Per DR1295, this means that binding a
const / rvalue reference to a bit-field no longer "binds directly", and per
P0135R1, this means that we materialize a temporary in reference binding
after adjusting cv-qualifiers and before performing a derived-to-base cast.

In C++11 onwards, this should have fixed the last case where we would
materialize a temporary of the wrong type (with a subobject adjustment inside
the MaterializeTemporaryExpr instead of outside), but we still have to deal
with that possibility in C++98, unless we want to start using xvalues to
represent materialized temporaries there too.

Modified:
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/Sema/SemaCast.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
    cfe/trunk/test/CXX/drs/dr12xx.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp
    cfe/trunk/test/SemaCXX/member-init.cpp
    cfe/trunk/test/SemaCXX/microsoft-new-delete.cpp
    cfe/trunk/test/SemaCXX/reinterpret-cast.cpp

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Fri Dec  9 12:49:13 2016
@@ -668,6 +668,9 @@ public:
     /// temporary object, which is permitted (but not required) by
     /// C++98/03 but not C++0x.
     SK_ExtraneousCopyToTemporary,
+    /// \brief Direct-initialization from a reference-related object in the
+    /// final stage of class copy-initialization.
+    SK_FinalCopy,
     /// \brief Perform a user-defined conversion, either via a conversion
     /// function or via a constructor.
     SK_UserConversion,
@@ -805,6 +808,10 @@ public:
     FK_ReferenceInitOverloadFailed,
     /// \brief Non-const lvalue reference binding to a temporary.
     FK_NonConstLValueReferenceBindingToTemporary,
+    /// \brief Non-const lvalue reference binding to a bit-field.
+    FK_NonConstLValueReferenceBindingToBitfield,
+    /// \brief Non-const lvalue reference binding to a vector element.
+    FK_NonConstLValueReferenceBindingToVectorElement,
     /// \brief Non-const lvalue reference binding to an lvalue of unrelated
     /// type.
     FK_NonConstLValueReferenceBindingToUnrelated,
@@ -1028,6 +1035,10 @@ public:
   /// \param T The type of the temporary being created.
   void AddExtraneousCopyToTemporary(QualType T);
 
+  /// \brief Add a new step that makes a copy of the input to an object of
+  /// the given type, as the final step in class copy-initialization.
+  void AddFinalCopy(QualType T);
+
   /// \brief Add a new step invoking a conversion function, which is either
   /// a constructor or a conversion function.
   void AddUserConversionStep(FunctionDecl *Function,

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Dec  9 12:49:13 2016
@@ -76,8 +76,8 @@ namespace {
       const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
                                                                Adjustments);
       // Keep any cv-qualifiers from the reference if we generated a temporary
-      // for it.
-      if (Inner != Temp)
+      // for it directly. Otherwise use the type after adjustment.
+      if (!Adjustments.empty())
         return Inner->getType();
     }
 

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Fri Dec  9 12:49:13 2016
@@ -1164,7 +1164,8 @@ CFGBlock *CFGBuilder::addInitializer(CXX
 /// \brief Retrieve the type of the temporary object whose lifetime was 
 /// extended by a local reference with the given initializer.
 static QualType getReferenceInitTemporaryType(ASTContext &Context,
-                                              const Expr *Init) {
+                                              const Expr *Init,
+                                              bool *FoundMTE = nullptr) {
   while (true) {
     // Skip parentheses.
     Init = Init->IgnoreParens();
@@ -1179,6 +1180,8 @@ static QualType getReferenceInitTemporar
     if (const MaterializeTemporaryExpr *MTE
           = dyn_cast<MaterializeTemporaryExpr>(Init)) {
       Init = MTE->GetTemporaryExpr();
+      if (FoundMTE)
+        *FoundMTE = true;
       continue;
     }
     
@@ -1370,13 +1373,12 @@ LocalScope* CFGBuilder::addLocalScopeFor
     const Expr *Init = VD->getInit();
     if (!Init)
       return Scope;
-    if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init))
-      Init = EWC->getSubExpr();
-    if (!isa<MaterializeTemporaryExpr>(Init))
-      return Scope;
 
     // Lifetime-extending a temporary.
-    QT = getReferenceInitTemporaryType(*Context, Init);
+    bool FoundMTE = false;
+    QT = getReferenceInitTemporaryType(*Context, Init, &FoundMTE);
+    if (!FoundMTE)
+      return Scope;
   }
 
   // Check for constant size array. Set type to array element type.

Modified: cfe/trunk/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCast.cpp Fri Dec  9 12:49:13 2016
@@ -1517,6 +1517,9 @@ TryStaticImplicitCast(Sema &Self, ExprRe
         ? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
     : InitializationKind::CreateCast(OpRange);
   Expr *SrcExprRaw = SrcExpr.get();
+  // FIXME: Per DR242, we should check for an implicit conversion sequence
+  // or for a constructor that could be invoked by direct-initialization
+  // here, not for an initialization sequence.
   InitializationSequence InitSeq(Self, Entity, InitKind, SrcExprRaw);
 
   // At this point of CheckStaticCast, if the destination is a reference,
@@ -1652,7 +1655,8 @@ static TryCastResult TryConstCast(Sema &
   if (NeedToMaterializeTemporary)
     // This is a const_cast from a class prvalue to an rvalue reference type.
     // Materialize a temporary to store the result of the conversion.
-    SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
+    SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcExpr.get()->getType(),
+                                                  SrcExpr.get(),
                                                   /*IsLValueReference*/ false);
 
   return TC_Success;
@@ -1916,7 +1920,10 @@ static TryCastResult TryReinterpretCast(
     switch (SrcExpr.get()->getObjectKind()) {
     case OK_Ordinary:
       break;
-    case OK_BitField:        inappropriate = "bit-field";           break;
+    case OK_BitField:
+      msg = diag::err_bad_cxx_cast_bitfield;
+      return TC_NotApplicable;
+      // FIXME: Use a specific diagnostic for the rest of these cases.
     case OK_VectorComponent: inappropriate = "vector element";      break;
     case OK_ObjCProperty:    inappropriate = "property expression"; break;
     case OK_ObjCSubscript:   inappropriate = "container subscripting expression"; 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Dec  9 12:49:13 2016
@@ -5411,13 +5411,19 @@ QualType Sema::CXXCheckConditionalOperan
     if (CompareReferenceRelationship(
             QuestionLoc, LTy, RTy, DerivedToBase,
             ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
-        !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion) {
+        !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+        // [...] subject to the constraint that the reference must bind
+        // directly [...]
+        !RHS.get()->refersToBitField() &&
+        !RHS.get()->refersToVectorElement()) {
       RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
       RTy = RHS.get()->getType();
     } else if (CompareReferenceRelationship(
                    QuestionLoc, RTy, LTy, DerivedToBase,
                    ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
-               !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion) {
+               !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+               !LHS.get()->refersToBitField() &&
+               !LHS.get()->refersToVectorElement()) {
       LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
       LTy = LHS.get()->getType();
     }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Dec  9 12:49:13 2016
@@ -3048,6 +3048,7 @@ void InitializationSequence::Step::Destr
   case SK_CastDerivedToBaseLValue:
   case SK_BindReference:
   case SK_BindReferenceToTemporary:
+  case SK_FinalCopy:
   case SK_ExtraneousCopyToTemporary:
   case SK_UserConversion:
   case SK_QualificationConversionRValue:
@@ -3082,7 +3083,14 @@ void InitializationSequence::Step::Destr
 }
 
 bool InitializationSequence::isDirectReferenceBinding() const {
-  return !Steps.empty() && Steps.back().Kind == SK_BindReference;
+  // There can be some lvalue adjustments after the SK_BindReference step.
+  for (auto I = Steps.rbegin(); I != Steps.rend(); ++I) {
+    if (I->Kind == SK_BindReference)
+      return true;
+    if (I->Kind == SK_BindReferenceToTemporary)
+      return false;
+  }
+  return false;
 }
 
 bool InitializationSequence::isAmbiguous() const {
@@ -3099,6 +3107,8 @@ bool InitializationSequence::isAmbiguous
   case FK_IncompatWideStringIntoWideChar:
   case FK_AddressOfOverloadFailed: // FIXME: Could do better
   case FK_NonConstLValueReferenceBindingToTemporary:
+  case FK_NonConstLValueReferenceBindingToBitfield:
+  case FK_NonConstLValueReferenceBindingToVectorElement:
   case FK_NonConstLValueReferenceBindingToUnrelated:
   case FK_RValueReferenceBindingToLValue:
   case FK_ReferenceInitDropsQualifiers:
@@ -3167,6 +3177,13 @@ void InitializationSequence::AddReferenc
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddFinalCopy(QualType T) {
+  Step S;
+  S.Kind = SK_FinalCopy;
+  S.Type = T;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) {
   Step S;
   S.Kind = SK_ExtraneousCopyToTemporary;
@@ -4002,12 +4019,10 @@ static void TryListInitialization(Sema &
 
 /// \brief Try a reference initialization that involves calling a conversion
 /// function.
-static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
-                                             const InitializedEntity &Entity,
-                                             const InitializationKind &Kind,
-                                             Expr *Initializer,
-                                             bool AllowRValues,
-                                             InitializationSequence &Sequence) {
+static OverloadingResult TryRefInitWithConversionFunction(
+    Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
+    Expr *Initializer, bool AllowRValues, bool IsLValueRef,
+    InitializationSequence &Sequence) {
   QualType DestType = Entity.getType();
   QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
   QualType T1 = cv1T1.getUnqualifiedType();
@@ -4123,58 +4138,68 @@ static OverloadingResult TryRefInitWithC
   // use this initialization. Mark it as referenced.
   Function->setReferenced();
 
-  // Compute the returned type of the conversion.
+  // Compute the returned type and value kind of the conversion.
+  QualType cv3T3;
   if (isa<CXXConversionDecl>(Function))
-    T2 = Function->getReturnType();
+    cv3T3 = Function->getReturnType();
   else
-    T2 = cv1T1;
+    cv3T3 = T1;
 
-  // Add the user-defined conversion step.
-  bool HadMultipleCandidates = (CandidateSet.size() > 1);
-  Sequence.AddUserConversionStep(Function, Best->FoundDecl,
-                                 T2.getNonLValueExprType(S.Context),
-                                 HadMultipleCandidates);
-
-  // Determine whether we need to perform derived-to-base or
-  // cv-qualification adjustments.
   ExprValueKind VK = VK_RValue;
-  if (T2->isLValueReferenceType())
+  if (cv3T3->isLValueReferenceType())
     VK = VK_LValue;
-  else if (const RValueReferenceType *RRef = T2->getAs<RValueReferenceType>())
+  else if (const auto *RRef = cv3T3->getAs<RValueReferenceType>())
     VK = RRef->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue;
+  cv3T3 = cv3T3.getNonLValueExprType(S.Context);
 
+  // Add the user-defined conversion step.
+  bool HadMultipleCandidates = (CandidateSet.size() > 1);
+  Sequence.AddUserConversionStep(Function, Best->FoundDecl, cv3T3,
+                                 HadMultipleCandidates);
+
+  // Determine whether we'll need to perform derived-to-base adjustments or
+  // other conversions.
   bool NewDerivedToBase = false;
   bool NewObjCConversion = false;
   bool NewObjCLifetimeConversion = false;
   Sema::ReferenceCompareResult NewRefRelationship
-    = S.CompareReferenceRelationship(DeclLoc, T1,
-                                     T2.getNonLValueExprType(S.Context),
+    = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
                                      NewDerivedToBase, NewObjCConversion,
                                      NewObjCLifetimeConversion);
+
+  // Add the final conversion sequence, if necessary.
   if (NewRefRelationship == Sema::Ref_Incompatible) {
-    // If the type we've converted to is not reference-related to the
-    // type we're looking for, then there is another conversion step
-    // we need to perform to produce a temporary of the right type
-    // that we'll be binding to.
+    assert(!isa<CXXConstructorDecl>(Function) &&
+           "should not have conversion after constructor");
+
     ImplicitConversionSequence ICS;
     ICS.setStandard();
     ICS.Standard = Best->FinalConversion;
-    T2 = ICS.Standard.getToType(2);
-    Sequence.AddConversionSequenceStep(ICS, T2);
-  } else if (NewDerivedToBase)
-    Sequence.AddDerivedToBaseCastStep(
-                                S.Context.getQualifiedType(T1,
-                                  T2.getNonReferenceType().getQualifiers()),
-                                      VK);
-  else if (NewObjCConversion)
-    Sequence.AddObjCObjectConversionStep(
-                                S.Context.getQualifiedType(T1,
-                                  T2.getNonReferenceType().getQualifiers()));
+    Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2));
+
+    // Every implicit conversion results in a prvalue, except for a glvalue
+    // derived-to-base conversion, which we handle below.
+    cv3T3 = ICS.Standard.getToType(2);
+    VK = VK_RValue;
+  }
 
-  if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers())
-    Sequence.AddQualificationConversionStep(cv1T1, VK);
+  //   If the converted initializer is a prvalue, its type T4 is adjusted to
+  //   type "cv1 T4" and the temporary materialization conversion is applied.
+  //
+  // We adjust the cv-qualifications to match the reference regardless of
+  // whether we have a prvalue so that the AST records the change. In this
+  // case, T4 is "cv3 T3".
+  QualType cv1T4 = S.Context.getQualifiedType(cv3T3, cv1T1.getQualifiers());
+  if (cv1T4.getQualifiers() != cv3T3.getQualifiers())
+    Sequence.AddQualificationConversionStep(cv1T4, VK);
+  Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue);
+  VK = IsLValueRef ? VK_LValue : VK_XValue;
+
+  if (NewDerivedToBase)
+    Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
+  else if (NewObjCConversion)
+    Sequence.AddObjCObjectConversionStep(cv1T1);
 
-  Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType());
   return OR_Success;
 }
 
@@ -4208,54 +4233,11 @@ static void TryReferenceInitialization(S
                                  T1Quals, cv2T2, T2, T2Quals, Sequence);
 }
 
-/// Converts the target of reference initialization so that it has the
-/// appropriate qualifiers and value kind.
-///
-/// In this case, 'x' is an 'int' lvalue, but it needs to be 'const int'.
-/// \code
-///   int x;
-///   const int &r = x;
-/// \endcode
-///
-/// In this case the reference is binding to a bitfield lvalue, which isn't
-/// valid. Perform a load to create a lifetime-extended temporary instead.
-/// \code
-///   const int &r = someStruct.bitfield;
-/// \endcode
-static ExprValueKind
-convertQualifiersAndValueKindIfNecessary(Sema &S,
-                                         InitializationSequence &Sequence,
-                                         Expr *Initializer,
-                                         QualType cv1T1,
-                                         Qualifiers T1Quals,
-                                         Qualifiers T2Quals,
-                                         bool IsLValueRef) {
-  bool IsNonAddressableType = Initializer->refersToBitField() ||
-                              Initializer->refersToVectorElement();
-
-  if (IsNonAddressableType) {
-    // C++11 [dcl.init.ref]p5: [...] Otherwise, the reference shall be an
-    // lvalue reference to a non-volatile const type, or the reference shall be
-    // an rvalue reference.
-    //
-    // If not, we can't make a temporary and bind to that. Give up and allow the
-    // error to be diagnosed later.
-    if (IsLValueRef && (!T1Quals.hasConst() || T1Quals.hasVolatile())) {
-      assert(Initializer->isGLValue());
-      return Initializer->getValueKind();
-    }
-
-    // Force a load so we can materialize a temporary.
-    Sequence.AddLValueToRValueStep(cv1T1.getUnqualifiedType());
-    return VK_RValue;
-  }
-
-  if (T1Quals != T2Quals) {
-    Sequence.AddQualificationConversionStep(cv1T1,
-                                            Initializer->getValueKind());
-  }
-
-  return Initializer->getValueKind();
+/// Determine whether an expression is a non-referenceable glvalue (one to
+/// which a reference can never bind). Attemting to bind a reference to
+/// such a glvalue will always create a temporary.
+static bool isNonReferenceableGLValue(Expr *E) {
+  return E->refersToBitField() || E->refersToVectorElement();
 }
 
 /// \brief Reference initialization without resolving overloaded functions.
@@ -4293,31 +4275,28 @@ static void TryReferenceInitializationCo
   OverloadingResult ConvOvlResult = OR_Success;
   bool T1Function = T1->isFunctionType();
   if (isLValueRef || T1Function) {
-    if (InitCategory.isLValue() &&
+    if (InitCategory.isLValue() && !isNonReferenceableGLValue(Initializer) &&
         (RefRelationship == Sema::Ref_Compatible ||
          (Kind.isCStyleOrFunctionalCast() &&
           RefRelationship == Sema::Ref_Related))) {
       //   - is an lvalue (but is not a bit-field), and "cv1 T1" is
       //     reference-compatible with "cv2 T2," or
-      //
-      // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a
-      // bit-field when we're determining whether the reference initialization
-      // can occur. However, we do pay attention to whether it is a bit-field
-      // to decide whether we're actually binding to a temporary created from
-      // the bit-field.
+      if (T1Quals != T2Quals)
+        // Convert to cv1 T2. This should only add qualifiers unless this is a
+        // c-style cast. The removal of qualifiers in that case notionally
+        // happens after the reference binding, but that doesn't matter.
+        Sequence.AddQualificationConversionStep(
+            S.Context.getQualifiedType(T2, T1Quals),
+            Initializer->getValueKind());
       if (DerivedToBase)
-        Sequence.AddDerivedToBaseCastStep(
-                         S.Context.getQualifiedType(T1, T2Quals),
-                         VK_LValue);
+        Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
       else if (ObjCConversion)
-        Sequence.AddObjCObjectConversionStep(
-                                     S.Context.getQualifiedType(T1, T2Quals));
+        Sequence.AddObjCObjectConversionStep(cv1T1);
 
-      ExprValueKind ValueKind =
-        convertQualifiersAndValueKindIfNecessary(S, Sequence, Initializer,
-                                                 cv1T1, T1Quals, T2Quals,
-                                                 isLValueRef);
-      Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue);
+      // We only create a temporary here when binding a reference to a
+      // bit-field or vector element. Those cases are't supposed to be
+      // handled by this bullet, but the outcome is the same either way.
+      Sequence.AddReferenceBindingStep(cv1T1, false);
       return;
     }
 
@@ -4332,7 +4311,8 @@ static void TryReferenceInitializationCo
     if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() &&
         (isLValueRef || InitCategory.isRValue())) {
       ConvOvlResult = TryRefInitWithConversionFunction(
-          S, Entity, Kind, Initializer, /*AllowRValues*/isRValueRef, Sequence);
+          S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef,
+          /*IsLValueRef*/ isLValueRef, Sequence);
       if (ConvOvlResult == OR_Success)
         return;
       if (ConvOvlResult != OR_No_Viable_Function)
@@ -4352,33 +4332,51 @@ static void TryReferenceInitializationCo
       Sequence.SetOverloadFailure(
                         InitializationSequence::FK_ReferenceInitOverloadFailed,
                                   ConvOvlResult);
-    else
-      Sequence.SetFailed(InitCategory.isLValue()
-        ? (RefRelationship == Sema::Ref_Related
-             ? InitializationSequence::FK_ReferenceInitDropsQualifiers
-             : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated)
-        : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
-
+    else if (!InitCategory.isLValue())
+      Sequence.SetFailed(
+          InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+    else {
+      InitializationSequence::FailureKind FK;
+      switch (RefRelationship) {
+      case Sema::Ref_Compatible:
+        if (Initializer->refersToBitField())
+          FK = InitializationSequence::
+              FK_NonConstLValueReferenceBindingToBitfield;
+        else if (Initializer->refersToVectorElement())
+          FK = InitializationSequence::
+              FK_NonConstLValueReferenceBindingToVectorElement;
+        else
+          llvm_unreachable("unexpected kind of compatible initializer");
+        break;
+      case Sema::Ref_Related:
+        FK = InitializationSequence::FK_ReferenceInitDropsQualifiers;
+        break;
+      case Sema::Ref_Incompatible:
+        FK = InitializationSequence::
+            FK_NonConstLValueReferenceBindingToUnrelated;
+        break;
+      }
+      Sequence.SetFailed(FK);
+    }
     return;
   }
 
   //    - If the initializer expression
-  // C++14-and-before:
-  //      - is an xvalue, class prvalue, array prvalue, or function lvalue and
-  //        "cv1 T1" is reference-compatible with "cv2 T2"
-  // C++1z:
-  //      - is an rvalue or function lvalue and "cv1 T1" is reference-compatible
-  //        with "cv2 T2"
-  // Note: functions are handled below.
+  //      - is an
+  // [<=14] xvalue (but not a bit-field), class prvalue, array prvalue, or
+  // [1z]   rvalue (but not a bit-field) or
+  //        function lvalue and "cv1 T1" is reference-compatible with "cv2 T2"
+  //
+  // Note: functions are handled above and below rather than here...
   if (!T1Function &&
       (RefRelationship == Sema::Ref_Compatible ||
        (Kind.isCStyleOrFunctionalCast() &&
         RefRelationship == Sema::Ref_Related)) &&
-      (InitCategory.isXValue() ||
+      ((InitCategory.isXValue() && !isNonReferenceableGLValue(Initializer)) ||
        (InitCategory.isPRValue() &&
         (S.getLangOpts().CPlusPlus1z || T2->isRecordType() ||
          T2->isArrayType())))) {
-    ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue : VK_RValue;
+    ExprValueKind ValueKind = InitCategory.isXValue() ? VK_XValue : VK_RValue;
     if (InitCategory.isPRValue() && T2->isRecordType()) {
       // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
       // compiler the freedom to perform a copy here or bind to the
@@ -4395,19 +4393,22 @@ static void TryReferenceInitializationCo
         CheckCXX98CompatAccessibleCopy(S, Entity, Initializer);
     }
 
+    // C++1z [dcl.init.ref]/5.2.1.2:
+    //   If the converted initializer is a prvalue, its type T4 is adjusted
+    //   to type "cv1 T4" and the temporary materialization conversion is
+    //   applied.
+    QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1Quals);
+    if (T1Quals != T2Quals)
+      Sequence.AddQualificationConversionStep(cv1T4, ValueKind);
+    Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_RValue);
+    ValueKind = isLValueRef ? VK_LValue : VK_XValue;
+
+    //   In any case, the reference is bound to the resulting glvalue (or to
+    //   an appropriate base class subobject).
     if (DerivedToBase)
-      Sequence.AddDerivedToBaseCastStep(S.Context.getQualifiedType(T1, T2Quals),
-                                        ValueKind);
+      Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
     else if (ObjCConversion)
-      Sequence.AddObjCObjectConversionStep(
-                                       S.Context.getQualifiedType(T1, T2Quals));
-
-    ValueKind = convertQualifiersAndValueKindIfNecessary(S, Sequence,
-                                                         Initializer, cv1T1,
-                                                         T1Quals, T2Quals,
-                                                         isLValueRef);
-
-    Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue);
+      Sequence.AddObjCObjectConversionStep(cv1T1);
     return;
   }
 
@@ -4420,7 +4421,8 @@ static void TryReferenceInitializationCo
   if (T2->isRecordType()) {
     if (RefRelationship == Sema::Ref_Incompatible) {
       ConvOvlResult = TryRefInitWithConversionFunction(
-          S, Entity, Kind, Initializer, /*AllowRValues*/true, Sequence);
+          S, Entity, Kind, Initializer, /*AllowRValues*/ true,
+          /*IsLValueRef*/ isLValueRef, Sequence);
       if (ConvOvlResult)
         Sequence.SetOverloadFailure(
             InitializationSequence::FK_ReferenceInitOverloadFailed,
@@ -4746,26 +4748,51 @@ static void TryUserDefinedConversion(Sem
     Sequence.AddUserConversionStep(Function, Best->FoundDecl,
                                    DestType.getUnqualifiedType(),
                                    HadMultipleCandidates);
+
+    // C++14 and before:
+    //   - if the function is a constructor, the call initializes a temporary
+    //     of the cv-unqualified version of the destination type. The [...]
+    //     temporary [...] is then used to direct-initialize, according to the
+    //     rules above, the object that is the destination of the
+    //     copy-initialization.
+    // Note that this just performs a simple object copy from the temporary.
+    //
+    // C++1z:
+    //   - if the function is a constructor, the call is a prvalue of the
+    //     cv-unqualified version of the destination type whose return object
+    //     is initialized by the constructor. The call is used to
+    //     direct-initialize, according to the rules above, the object that
+    //     is the destination of the copy-initialization.
+    // Therefore we need to do nothing further.
+    //
+    // FIXME: Mark this copy as extraneous.
+    if (!S.getLangOpts().CPlusPlus1z)
+      Sequence.AddFinalCopy(DestType);
     return;
   }
 
   // Add the user-defined conversion step that calls the conversion function.
   QualType ConvType = Function->getCallResultType();
+  Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
+                                 HadMultipleCandidates);
+
   if (ConvType->getAs<RecordType>()) {
-    // If we're converting to a class type, there may be an copy of
-    // the resulting temporary object (possible to create an object of
-    // a base class type). That copy is not a separate conversion, so
-    // we just make a note of the actual destination type (possibly a
-    // base class of the type returned by the conversion function) and
-    // let the user-defined conversion step handle the conversion.
-    Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType,
-                                   HadMultipleCandidates);
+    //   The call is used to direct-initialize [...] the object that is the
+    //   destination of the copy-initialization.
+    //
+    // In C++1z, this does not call a constructor if we enter /17.6.1:
+    //   - If the initializer expression is a prvalue and the cv-unqualified
+    //     version of the source type is the same as the class of the
+    //     destination [... do not make an extra copy]
+    //
+    // FIXME: Mark this copy as extraneous.
+    if (!S.getLangOpts().CPlusPlus1z ||
+        Function->getReturnType()->isReferenceType() ||
+        !S.Context.hasSameUnqualifiedType(ConvType, DestType))
+      Sequence.AddFinalCopy(DestType);
     return;
   }
 
-  Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
-                                 HadMultipleCandidates);
-
   // If the conversion following the call to the conversion function
   // is interesting, add it as a separate step.
   if (Best->FinalConversion.First || Best->FinalConversion.Second ||
@@ -5382,7 +5409,7 @@ static bool shouldBindAsTemporary(const
 
 /// \brief Whether the given entity, when initialized with an object
 /// created for that initialization, requires destruction.
-static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
+static bool shouldDestroyEntity(const InitializedEntity &Entity) {
   switch (Entity.getKind()) {
     case InitializedEntity::EK_Result:
     case InitializedEntity::EK_New:
@@ -5686,11 +5713,6 @@ void InitializationSequence::PrintInitLo
       << Entity.getMethodDecl()->getDeclName();
 }
 
-static bool isReferenceBinding(const InitializationSequence::Step &s) {
-  return s.Kind == InitializationSequence::SK_BindReference ||
-         s.Kind == InitializationSequence::SK_BindReferenceToTemporary;
-}
-
 /// Returns true if the parameters describe a constructor initialization of
 /// an explicit temporary object, e.g. "Point(x, y)".
 static bool isExplicitTemporary(const InitializedEntity &Entity,
@@ -6392,6 +6414,7 @@ InitializationSequence::Perform(Sema &S,
   case SK_CastDerivedToBaseLValue:
   case SK_BindReference:
   case SK_BindReferenceToTemporary:
+  case SK_FinalCopy:
   case SK_ExtraneousCopyToTemporary:
   case SK_UserConversion:
   case SK_QualificationConversionLValue:
@@ -6479,30 +6502,6 @@ InitializationSequence::Perform(Sema &S,
     }
 
     case SK_BindReference:
-      // References cannot bind to bit-fields (C++ [dcl.init.ref]p5).
-      if (CurInit.get()->refersToBitField()) {
-        // We don't necessarily have an unambiguous source bit-field.
-        FieldDecl *BitField = CurInit.get()->getSourceBitField();
-        S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
-          << Entity.getType().isVolatileQualified()
-          << (BitField ? BitField->getDeclName() : DeclarationName())
-          << (BitField != nullptr)
-          << CurInit.get()->getSourceRange();
-        if (BitField)
-          S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
-
-        return ExprError();
-      }
-
-      if (CurInit.get()->refersToVectorElement()) {
-        // References cannot bind to vector elements.
-        S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
-          << Entity.getType().isVolatileQualified()
-          << CurInit.get()->getSourceRange();
-        PrintInitLocationNote(S, Entity);
-        return ExprError();
-      }
-
       // Reference binding does not have any corresponding ASTs.
 
       // Check exception specifications
@@ -6532,15 +6531,15 @@ InitializationSequence::Perform(Sema &S,
 
       // Materialize the temporary into memory.
       MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
-          Entity.getType().getNonReferenceType(), CurInit.get(),
-          Entity.getType()->isLValueReferenceType());
+          Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType());
 
       // Maybe lifetime-extend the temporary's subobjects to match the
       // entity's lifetime.
       if (const InitializedEntity *ExtendingEntity =
               getEntityForTemporaryLifetimeExtension(&Entity))
         if (performReferenceExtension(MTE, ExtendingEntity))
-          warnOnLifetimeExtension(S, Entity, CurInit.get(), /*IsInitializerList=*/false,
+          warnOnLifetimeExtension(S, Entity, CurInit.get(),
+                                  /*IsInitializerList=*/false,
                                   ExtendingEntity->getDecl());
 
       // If we're binding to an Objective-C object that has lifetime, we
@@ -6557,6 +6556,18 @@ InitializationSequence::Perform(Sema &S,
       break;
     }
 
+    case SK_FinalCopy:
+      // If the overall initialization is initializing a temporary, we already
+      // bound our argument if it was necessary to do so. If not (if we're
+      // ultimately initializing a non-temporary), our argument needs to be
+      // bound since it's initializing a function parameter.
+      // FIXME: This is a mess. Rationalize temporary destruction.
+      if (!shouldBindAsTemporary(Entity))
+        CurInit = S.MaybeBindToTemporary(CurInit.get());
+      CurInit = CopyObject(S, Step->Type, Entity, CurInit,
+                           /*IsExtraneousCopy=*/false);
+      break;
+
     case SK_ExtraneousCopyToTemporary:
       CurInit = CopyObject(S, Step->Type, Entity, CurInit,
                            /*IsExtraneousCopy=*/true);
@@ -6566,7 +6577,6 @@ InitializationSequence::Perform(Sema &S,
       // We have a user-defined conversion that invokes either a constructor
       // or a conversion function.
       CastKind CastKind;
-      bool IsCopy = false;
       FunctionDecl *Fn = Step->Function.Function;
       DeclAccessPair FoundFn = Step->Function.FoundDecl;
       bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
@@ -6575,7 +6585,6 @@ InitializationSequence::Perform(Sema &S,
         // Build a call to the selected constructor.
         SmallVector<Expr*, 8> ConstructorArgs;
         SourceLocation Loc = CurInit.get()->getLocStart();
-        CurInit.get(); // Ownership transferred into MultiExprArg, below.
 
         // Determine the arguments required to actually perform the constructor
         // call.
@@ -6604,11 +6613,6 @@ InitializationSequence::Perform(Sema &S,
           return ExprError();
 
         CastKind = CK_ConstructorConversion;
-        QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
-        if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
-            S.IsDerivedFrom(Loc, SourceType, Class))
-          IsCopy = true;
-
         CreatedObject = true;
       } else {
         // Build a call to the conversion function.
@@ -6621,48 +6625,35 @@ InitializationSequence::Perform(Sema &S,
         // FIXME: Should we move this initialization into a separate
         // derived-to-base conversion? I believe the answer is "no", because
         // we don't want to turn off access control here for c-style casts.
-        ExprResult CurInitExprRes =
-          S.PerformObjectArgumentInitialization(CurInit.get(),
-                                                /*Qualifier=*/nullptr,
-                                                FoundFn, Conversion);
-        if(CurInitExprRes.isInvalid())
+        CurInit = S.PerformObjectArgumentInitialization(CurInit.get(),
+                                                        /*Qualifier=*/nullptr,
+                                                        FoundFn, Conversion);
+        if (CurInit.isInvalid())
           return ExprError();
-        CurInit = CurInitExprRes;
 
         // Build the actual call to the conversion function.
         CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
                                            HadMultipleCandidates);
-        if (CurInit.isInvalid() || !CurInit.get())
+        if (CurInit.isInvalid())
           return ExprError();
 
         CastKind = CK_UserDefinedConversion;
-
         CreatedObject = Conversion->getReturnType()->isRecordType();
       }
 
-      // C++14 and before:
-      //   - if the function is a constructor, the call initializes a temporary
-      //     of the cv-unqualified version of the destination type [...]
-      // C++1z:
-      //   - if the function is a constructor, the call is a prvalue of the
-      //     cv-unqualified version of the destination type whose return object
-      //     is initialized by the constructor [...]
-      // Both:
-      //     The [..] call is used to direct-initialize, according to the rules
-      //     above, the object that is the destination of the
-      //     copy-initialization.
-      // In C++14 and before, that always means the "constructors are
-      // considered" bullet, because we have arrived at a reference-related
-      // type. In C++1z, it only means that if the types are different or we
-      // didn't produce a prvalue, so just check for that case here.
-      bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back());
-      if (S.getLangOpts().CPlusPlus1z && CurInit.get()->isRValue() &&
-          S.Context.hasSameUnqualifiedType(
-              Entity.getType().getNonReferenceType(), CurInit.get()->getType()))
-        RequiresCopy = false;
-      bool MaybeBindToTemp = RequiresCopy || shouldBindAsTemporary(Entity);
+      CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(),
+                                         CastKind, CurInit.get(), nullptr,
+                                         CurInit.get()->getValueKind());
 
-      if (!MaybeBindToTemp && CreatedObject && shouldDestroyTemporary(Entity)) {
+      if (shouldBindAsTemporary(Entity))
+        // The overall entity is temporary, so this expression should be
+        // destroyed at the end of its full-expression.
+        CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>());
+      else if (CreatedObject && shouldDestroyEntity(Entity)) {
+        // The object outlasts the full-expression, but we need to prepare for
+        // a destructor being run on it.
+        // FIXME: It makes no sense to do this here. This should happen
+        // regardless of how we initialized the entity.
         QualType T = CurInit.get()->getType();
         if (const RecordType *Record = T->getAs<RecordType>()) {
           CXXDestructorDecl *Destructor
@@ -6674,15 +6665,6 @@ InitializationSequence::Perform(Sema &S,
             return ExprError();
         }
       }
-
-      CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(),
-                                         CastKind, CurInit.get(), nullptr,
-                                         CurInit.get()->getValueKind());
-      if (MaybeBindToTemp)
-        CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>());
-      if (RequiresCopy)
-        CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
-                             CurInit, /*IsExtraneousCopy=*/false);
       break;
     }
 
@@ -7350,6 +7332,25 @@ bool InitializationSequence::Diagnose(Se
       << Args[0]->getSourceRange();
     break;
 
+  case FK_NonConstLValueReferenceBindingToBitfield: {
+    // We don't necessarily have an unambiguous source bit-field.
+    FieldDecl *BitField = Args[0]->getSourceBitField();
+    S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
+      << DestType.isVolatileQualified()
+      << (BitField ? BitField->getDeclName() : DeclarationName())
+      << (BitField != nullptr)
+      << Args[0]->getSourceRange();
+    if (BitField)
+      S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
+    break;
+  }
+
+  case FK_NonConstLValueReferenceBindingToVectorElement:
+    S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
+      << DestType.isVolatileQualified()
+      << Args[0]->getSourceRange();
+    break;
+
   case FK_RValueReferenceBindingToLValue:
     S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
       << DestType.getNonReferenceType() << Args[0]->getType()
@@ -7647,6 +7648,14 @@ void InitializationSequence::dump(raw_os
       OS << "non-const lvalue reference bound to temporary";
       break;
 
+    case FK_NonConstLValueReferenceBindingToBitfield:
+      OS << "non-const lvalue reference bound to bit-field";
+      break;
+
+    case FK_NonConstLValueReferenceBindingToVectorElement:
+      OS << "non-const lvalue reference bound to vector element";
+      break;
+
     case FK_NonConstLValueReferenceBindingToUnrelated:
       OS << "non-const lvalue reference bound to unrelated type";
       break;
@@ -7743,15 +7752,15 @@ void InitializationSequence::dump(raw_os
       break;
 
     case SK_CastDerivedToBaseRValue:
-      OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")";
+      OS << "derived-to-base (rvalue)";
       break;
 
     case SK_CastDerivedToBaseXValue:
-      OS << "derived-to-base case (xvalue" << S->Type.getAsString() << ")";
+      OS << "derived-to-base (xvalue)";
       break;
 
     case SK_CastDerivedToBaseLValue:
-      OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")";
+      OS << "derived-to-base (lvalue)";
       break;
 
     case SK_BindReference:
@@ -7762,6 +7771,10 @@ void InitializationSequence::dump(raw_os
       OS << "bind reference to a temporary";
       break;
 
+    case SK_FinalCopy:
+      OS << "final copy in class direct-initialization";
+      break;
+
     case SK_ExtraneousCopyToTemporary:
       OS << "extraneous C++03 copy to temporary";
       break;

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Dec  9 12:49:13 2016
@@ -4773,6 +4773,9 @@ TryListConversion(Sema &S, InitListExpr
     // Type is an aggregate, argument is an init list. At this point it comes
     // down to checking whether the initialization works.
     // FIXME: Find out whether this parameter is consumed or not.
+    // FIXME: Expose SemaInit's aggregate initialization code so that we don't
+    // need to call into the initialization code here; overload resolution
+    // should not be doing that.
     InitializedEntity Entity =
         InitializedEntity::InitializeParameter(S.Context, ToType,
                                                /*Consumed=*/false);

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp Fri Dec  9 12:49:13 2016
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
 
-// CHECK: example0
+// CHECK-LABEL: example0
 void example0() {
   double d = 2.0;
   // CHECK: VarDecl{{.*}}rd 'double &'
@@ -14,14 +14,15 @@ void example0() {
 struct A { };
 struct B : A { } b;
 
-// CHECK: example1
+// CHECK-LABEL: example1
 void example1() {
   // CHECK: VarDecl{{.*}}ra 'struct A &'
   // CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
   A &ra = b;
   // CHECK: VarDecl{{.*}}rca 'const struct A &'
-  // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <NoOp>
-  // CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
+  // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
+  // CHECK-NOT: MaterializeTemporaryExpr
+  // CHECK: ImplicitCastExpr{{.*}}'const struct B' lvalue <NoOp>
   const A& rca = b;
 }
 
@@ -31,21 +32,23 @@ struct X {
   operator B();
 } x;
 
-// CHECK: example2
+// CHECK-LABEL: example2
 void example2() {
   // CHECK: VarDecl{{.*}}rca 'const struct A &'
-  // CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
-  // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
+  // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
+  // CHECK: MaterializeTemporaryExpr{{.*}}'const struct B'
+  // CHECK: ImplicitCastExpr{{.*}}'const struct B' <NoOp>
   // CHECK: CallExpr{{.*}}B
   const A &rca = f(); 
   // CHECK: VarDecl{{.*}}r 'const struct A &'
-  // CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
-  // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
+  // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
+  // CHECK: MaterializeTemporaryExpr{{.*}}'const struct B'
+  // CHECK: ImplicitCastExpr{{.*}}'const struct B' <NoOp>
   // CHECK: CXXMemberCallExpr{{.*}}'struct B'
   const A& r = x;
 }
 
-// CHECK: example3
+// CHECK-LABEL: example3
 void example3() {
   // CHECK: VarDecl{{.*}}rcd2 'const double &'
   // CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp Fri Dec  9 12:49:13 2016
@@ -41,7 +41,7 @@ namespace PR6066 {
 
 namespace test3 {
   struct A {
-    unsigned bitX : 4; // expected-note 4 {{bit-field is declared here}}
+    unsigned bitX : 4; // expected-note 3 {{bit-field is declared here}}
     unsigned bitY : 4; // expected-note {{bit-field is declared here}}
     unsigned var;
 
@@ -50,7 +50,7 @@ namespace test3 {
 
   void test(A *a) {
     unsigned &t0 = a->bitX; // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
-    unsigned &t1 = (unsigned&) a->bitX; // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
+    unsigned &t1 = (unsigned&) a->bitX; // expected-error {{C-style cast from bit-field lvalue to reference type 'unsigned int &'}}
     unsigned &t2 = const_cast<unsigned&>(a->bitX); // expected-error {{const_cast from bit-field lvalue to reference type 'unsigned int &'}}
     unsigned &t3 = (a->foo(), a->bitX); // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
     unsigned &t4 = (a->var ? a->bitX : a->bitY); // expected-error {{non-const reference cannot bind to bit-field}}

Modified: cfe/trunk/test/CXX/drs/dr12xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr12xx.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr12xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr12xx.cpp Fri Dec  9 12:49:13 2016
@@ -3,8 +3,6 @@
 // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
-// expected-no-diagnostics
-
 namespace dr1213 { // dr1213: 4.0
 #if __cplusplus >= 201103L
   using T = int[3];
@@ -27,3 +25,29 @@ struct Derived : Base {
   virtual Incomplete *meow();
 };
 } // dr1250
+
+namespace dr1295 {  // dr1295: 4.0
+  struct X {
+    unsigned bitfield : 4;
+  };
+
+  X x = {1};
+
+  unsigned const &r1 = static_cast<X &&>(x).bitfield; // expected-error 0-1{{C++11}}
+  unsigned const &r2 = static_cast<unsigned &&>(x.bitfield); // expected-error 0-1{{C++11}}
+
+  template<unsigned &r> struct Y {};
+  Y<x.bitfield> y;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{does not refer to any declaration}} expected-note at -3 {{here}}
+#else
+  // expected-error at -4 {{refers to subobject}}
+#endif
+
+#if __cplusplus >= 201103L
+  const unsigned other = 0;
+  using T = decltype(true ? other : x.bitfield);
+  using T = unsigned;
+#endif
+}
+

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Dec  9 12:49:13 2016
@@ -386,6 +386,18 @@ namespace FakeInitList {
   constexpr init_list_2_init_list_3_ints ils = { { { { 1, 2, 3 } }, { { 4, 5, 6 } } } };
 }
 
+namespace ConstAddedByReference {
+  const int &r = (0);
+  constexpr int n = r;
+
+  struct A { constexpr operator int() const { return 0; }};
+  struct B { constexpr operator const int() const { return 0; }};
+  const int &ra = A();
+  const int &rb = B();
+  constexpr int na = ra;
+  constexpr int nb = rb;
+}
+
 }
 
 constexpr int strcmp_ce(const char *p, const char *q) {

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp Fri Dec  9 12:49:13 2016
@@ -39,3 +39,8 @@ namespace NoexceptFunctionTypes {
   static_assert(A<int>().g());
   static_assert(A<int>()());
 }
+
+namespace Cxx17CD_NB_GB19 {
+  const int &r = 0;
+  constexpr int n = r;
+}

Modified: cfe/trunk/test/SemaCXX/member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-init.cpp Fri Dec  9 12:49:13 2016
@@ -87,7 +87,7 @@ namespace PR14838 {
   struct thing {};
   struct another {
     another() : r(thing()) {}
-    // expected-error at -1 {{temporary of type 'const PR14838::function' has private destructor}}
+    // expected-error at -1 {{temporary of type 'PR14838::function' has private destructor}}
     // expected-warning at -2 {{binding reference member 'r' to a temporary value}}
     const function &r; // expected-note {{reference member declared here}}
   } af;

Modified: cfe/trunk/test/SemaCXX/microsoft-new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/microsoft-new-delete.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/microsoft-new-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/microsoft-new-delete.cpp Fri Dec  9 12:49:13 2016
@@ -16,7 +16,7 @@ void *operator new(size_t, const noncopy
 void *q = new (nc) int[4]; // expected-error {{calling a private constructor}}
 
 struct bitfield { int n : 3; } bf; // expected-note {{here}}
-void *operator new[](size_t, int &);
+void *operator new[](size_t, int &); // expected-note {{passing argument to parameter here}}
 void *operator new(size_t, const int &);
 void *r = new (bf.n) int[4]; // expected-error {{non-const reference cannot bind to bit-field}}
 

Modified: cfe/trunk/test/SemaCXX/reinterpret-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/reinterpret-cast.cpp?rev=289250&r1=289249&r2=289250&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/reinterpret-cast.cpp (original)
+++ cfe/trunk/test/SemaCXX/reinterpret-cast.cpp Fri Dec  9 12:49:13 2016
@@ -125,7 +125,7 @@ void const_arrays() {
 
 namespace PR9564 {
   struct a { int a : 10; }; a x;
-  int *y = &reinterpret_cast<int&>(x.a); // expected-error {{not allowed}}
+  int *y = &reinterpret_cast<int&>(x.a); // expected-error {{reinterpret_cast from bit-field lvalue to reference type 'int &'}}
 
   __attribute((ext_vector_type(4))) typedef float v4;
   float& w(v4 &a) { return reinterpret_cast<float&>(a[1]); } // expected-error {{not allowed}}




More information about the cfe-commits mailing list