From b8c0f553ed6b7e52b12afa00ace3e30754482037 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 9 Dec 2016 18:49:13 +0000 Subject: [PATCH] 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. llvm-svn: 289250 --- clang/include/clang/Sema/Initialization.h | 11 + clang/lib/AST/ExprConstant.cpp | 4 +- clang/lib/Analysis/CFG.cpp | 14 +- clang/lib/Sema/SemaCast.cpp | 11 +- clang/lib/Sema/SemaExprCXX.cpp | 10 +- clang/lib/Sema/SemaInit.cpp | 471 +++++++++++---------- clang/lib/Sema/SemaOverload.cpp | 3 + .../dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp | 23 +- .../test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp | 4 +- clang/test/CXX/drs/dr12xx.cpp | 28 +- clang/test/SemaCXX/constant-expression-cxx11.cpp | 12 + clang/test/SemaCXX/constant-expression-cxx1z.cpp | 5 + clang/test/SemaCXX/member-init.cpp | 2 +- clang/test/SemaCXX/microsoft-new-delete.cpp | 2 +- clang/test/SemaCXX/reinterpret-cast.cpp | 2 +- 15 files changed, 344 insertions(+), 258 deletions(-) diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index 75e59c2..c7b163e 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -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, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fa5cb8c..e326510 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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(); } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index a4470c1..bf3cc05 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -1164,7 +1164,8 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { /// \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 getReferenceInitTemporaryType(ASTContext &Context, if (const MaterializeTemporaryExpr *MTE = dyn_cast(Init)) { Init = MTE->GetTemporaryExpr(); + if (FoundMTE) + *FoundMTE = true; continue; } @@ -1370,13 +1373,12 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, const Expr *Init = VD->getInit(); if (!Init) return Scope; - if (const ExprWithCleanups *EWC = dyn_cast(Init)) - Init = EWC->getSubExpr(); - if (!isa(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. diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index f4810fb..d1e37c0 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -1517,6 +1517,9 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ? 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 &Self, ExprResult &SrcExpr, 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(Sema &Self, ExprResult &SrcExpr, 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"; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 262235a..6acbd74 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5411,13 +5411,19 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, 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(); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index a0ea8e1..50e7b8e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3048,6 +3048,7 @@ void InitializationSequence::Step::Destroy() { 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::Destroy() { } 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() const { 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::AddReferenceBindingStep(QualType T, 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 &S, /// \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()->getPointeeType(); QualType T1 = cv1T1.getUnqualifiedType(); @@ -4123,58 +4138,68 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // 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(Function)) - T2 = Function->getReturnType(); + cv3T3 = Function->getReturnType(); else - T2 = cv1T1; - - // Add the user-defined conversion step. - bool HadMultipleCandidates = (CandidateSet.size() > 1); - Sequence.AddUserConversionStep(Function, Best->FoundDecl, - T2.getNonLValueExprType(S.Context), - HadMultipleCandidates); + cv3T3 = T1; - // 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()) + else if (const auto *RRef = cv3T3->getAs()) 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(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)); - if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) - Sequence.AddQualificationConversionStep(cv1T1, VK); + // 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 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(Sema &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 TryReferenceInitializationCore(Sema &S, 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)); - - ExprValueKind ValueKind = - convertQualifiersAndValueKindIfNecessary(S, Sequence, Initializer, - cv1T1, T1Quals, T2Quals, - isLValueRef); - Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); + Sequence.AddObjCObjectConversionStep(cv1T1); + + // 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 TryReferenceInitializationCore(Sema &S, 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 TryReferenceInitializationCore(Sema &S, 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 TryReferenceInitializationCore(Sema &S, 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 TryReferenceInitializationCore(Sema &S, 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(Sema &S, 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()) { - // 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 InitializedEntity &Entity) { /// \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::PrintInitLocationNote(Sema &S, << 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 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); - - if (!MaybeBindToTemp && CreatedObject && shouldDestroyTemporary(Entity)) { + CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(), + CastKind, CurInit.get(), nullptr, + CurInit.get()->getValueKind()); + + 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()); + 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()) { 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()); - if (RequiresCopy) - CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, - CurInit, /*IsExtraneousCopy=*/false); break; } @@ -7350,6 +7332,25 @@ bool InitializationSequence::Diagnose(Sema &S, << 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_ostream &OS) const { 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_ostream &OS) const { 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_ostream &OS) const { 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; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6985d69..57a45ee 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4773,6 +4773,9 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // 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); diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp index be1113d..052349c 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp @@ -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 A &ra = b; // CHECK: VarDecl{{.*}}rca 'const struct A &' - // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue - // CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue + // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue + // CHECK-NOT: MaterializeTemporaryExpr + // CHECK: ImplicitCastExpr{{.*}}'const struct B' lvalue 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' - // CHECK: ImplicitCastExpr{{.*}}'struct A' + // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue + // CHECK: MaterializeTemporaryExpr{{.*}}'const struct B' + // CHECK: ImplicitCastExpr{{.*}}'const struct B' // CHECK: CallExpr{{.*}}B const A &rca = f(); // CHECK: VarDecl{{.*}}r 'const struct A &' - // CHECK: ImplicitCastExpr{{.*}}'const struct A' - // CHECK: ImplicitCastExpr{{.*}}'struct A' + // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue + // CHECK: MaterializeTemporaryExpr{{.*}}'const struct B' + // CHECK: ImplicitCastExpr{{.*}}'const struct B' // CHECK: CXXMemberCallExpr{{.*}}'struct B' const A& r = x; } -// CHECK: example3 +// CHECK-LABEL: example3 void example3() { // CHECK: VarDecl{{.*}}rcd2 'const double &' // CHECK: ImplicitCastExpr{{.*}} diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp index 263f661..e775e8f 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp @@ -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(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}} diff --git a/clang/test/CXX/drs/dr12xx.cpp b/clang/test/CXX/drs/dr12xx.cpp index c4f980a..72d8d68 100644 --- a/clang/test/CXX/drs/dr12xx.cpp +++ b/clang/test/CXX/drs/dr12xx.cpp @@ -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).bitfield; // expected-error 0-1{{C++11}} + unsigned const &r2 = static_cast(x.bitfield); // expected-error 0-1{{C++11}} + + template struct Y {}; + Y y; +#if __cplusplus <= 201402L + // expected-error@-2 {{does not refer to any declaration}} expected-note@-3 {{here}} +#else + // expected-error@-4 {{refers to subobject}} +#endif + +#if __cplusplus >= 201103L + const unsigned other = 0; + using T = decltype(true ? other : x.bitfield); + using T = unsigned; +#endif +} + diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 8ecf4a4..a441405 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -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) { diff --git a/clang/test/SemaCXX/constant-expression-cxx1z.cpp b/clang/test/SemaCXX/constant-expression-cxx1z.cpp index a045234..1563586 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1z.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1z.cpp @@ -39,3 +39,8 @@ namespace NoexceptFunctionTypes { static_assert(A().g()); static_assert(A()()); } + +namespace Cxx17CD_NB_GB19 { + const int &r = 0; + constexpr int n = r; +} diff --git a/clang/test/SemaCXX/member-init.cpp b/clang/test/SemaCXX/member-init.cpp index 836c1f7..20e4cec 100644 --- a/clang/test/SemaCXX/member-init.cpp +++ b/clang/test/SemaCXX/member-init.cpp @@ -87,7 +87,7 @@ namespace PR14838 { struct thing {}; struct another { another() : r(thing()) {} - // expected-error@-1 {{temporary of type 'const PR14838::function' has private destructor}} + // expected-error@-1 {{temporary of type 'PR14838::function' has private destructor}} // expected-warning@-2 {{binding reference member 'r' to a temporary value}} const function &r; // expected-note {{reference member declared here}} } af; diff --git a/clang/test/SemaCXX/microsoft-new-delete.cpp b/clang/test/SemaCXX/microsoft-new-delete.cpp index b929e61..beba4d9 100644 --- a/clang/test/SemaCXX/microsoft-new-delete.cpp +++ b/clang/test/SemaCXX/microsoft-new-delete.cpp @@ -16,7 +16,7 @@ void *operator new(size_t, const noncopyable&); 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}} diff --git a/clang/test/SemaCXX/reinterpret-cast.cpp b/clang/test/SemaCXX/reinterpret-cast.cpp index 7c88dc0..6cc46d8 100644 --- a/clang/test/SemaCXX/reinterpret-cast.cpp +++ b/clang/test/SemaCXX/reinterpret-cast.cpp @@ -125,7 +125,7 @@ void const_arrays() { namespace PR9564 { struct a { int a : 10; }; a x; - int *y = &reinterpret_cast(x.a); // expected-error {{not allowed}} + int *y = &reinterpret_cast(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(a[1]); } // expected-error {{not allowed}} -- 2.7.4