forked from OSchip/llvm-project
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
This commit is contained in:
parent
0c1c3bbc78
commit
b8c0f553ed
|
@ -668,6 +668,9 @@ public:
|
||||||
/// temporary object, which is permitted (but not required) by
|
/// temporary object, which is permitted (but not required) by
|
||||||
/// C++98/03 but not C++0x.
|
/// C++98/03 but not C++0x.
|
||||||
SK_ExtraneousCopyToTemporary,
|
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
|
/// \brief Perform a user-defined conversion, either via a conversion
|
||||||
/// function or via a constructor.
|
/// function or via a constructor.
|
||||||
SK_UserConversion,
|
SK_UserConversion,
|
||||||
|
@ -805,6 +808,10 @@ public:
|
||||||
FK_ReferenceInitOverloadFailed,
|
FK_ReferenceInitOverloadFailed,
|
||||||
/// \brief Non-const lvalue reference binding to a temporary.
|
/// \brief Non-const lvalue reference binding to a temporary.
|
||||||
FK_NonConstLValueReferenceBindingToTemporary,
|
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
|
/// \brief Non-const lvalue reference binding to an lvalue of unrelated
|
||||||
/// type.
|
/// type.
|
||||||
FK_NonConstLValueReferenceBindingToUnrelated,
|
FK_NonConstLValueReferenceBindingToUnrelated,
|
||||||
|
@ -1028,6 +1035,10 @@ public:
|
||||||
/// \param T The type of the temporary being created.
|
/// \param T The type of the temporary being created.
|
||||||
void AddExtraneousCopyToTemporary(QualType T);
|
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
|
/// \brief Add a new step invoking a conversion function, which is either
|
||||||
/// a constructor or a conversion function.
|
/// a constructor or a conversion function.
|
||||||
void AddUserConversionStep(FunctionDecl *Function,
|
void AddUserConversionStep(FunctionDecl *Function,
|
||||||
|
|
|
@ -76,8 +76,8 @@ namespace {
|
||||||
const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
|
const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
|
||||||
Adjustments);
|
Adjustments);
|
||||||
// Keep any cv-qualifiers from the reference if we generated a temporary
|
// Keep any cv-qualifiers from the reference if we generated a temporary
|
||||||
// for it.
|
// for it directly. Otherwise use the type after adjustment.
|
||||||
if (Inner != Temp)
|
if (!Adjustments.empty())
|
||||||
return Inner->getType();
|
return Inner->getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1164,7 +1164,8 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
|
||||||
/// \brief Retrieve the type of the temporary object whose lifetime was
|
/// \brief Retrieve the type of the temporary object whose lifetime was
|
||||||
/// extended by a local reference with the given initializer.
|
/// extended by a local reference with the given initializer.
|
||||||
static QualType getReferenceInitTemporaryType(ASTContext &Context,
|
static QualType getReferenceInitTemporaryType(ASTContext &Context,
|
||||||
const Expr *Init) {
|
const Expr *Init,
|
||||||
|
bool *FoundMTE = nullptr) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Skip parentheses.
|
// Skip parentheses.
|
||||||
Init = Init->IgnoreParens();
|
Init = Init->IgnoreParens();
|
||||||
|
@ -1179,6 +1180,8 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context,
|
||||||
if (const MaterializeTemporaryExpr *MTE
|
if (const MaterializeTemporaryExpr *MTE
|
||||||
= dyn_cast<MaterializeTemporaryExpr>(Init)) {
|
= dyn_cast<MaterializeTemporaryExpr>(Init)) {
|
||||||
Init = MTE->GetTemporaryExpr();
|
Init = MTE->GetTemporaryExpr();
|
||||||
|
if (FoundMTE)
|
||||||
|
*FoundMTE = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,13 +1373,12 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
|
||||||
const Expr *Init = VD->getInit();
|
const Expr *Init = VD->getInit();
|
||||||
if (!Init)
|
if (!Init)
|
||||||
return Scope;
|
return Scope;
|
||||||
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init))
|
|
||||||
Init = EWC->getSubExpr();
|
|
||||||
if (!isa<MaterializeTemporaryExpr>(Init))
|
|
||||||
return Scope;
|
|
||||||
|
|
||||||
// Lifetime-extending a temporary.
|
// 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.
|
// Check for constant size array. Set type to array element type.
|
||||||
|
|
|
@ -1517,6 +1517,9 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
|
||||||
? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
|
? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
|
||||||
: InitializationKind::CreateCast(OpRange);
|
: InitializationKind::CreateCast(OpRange);
|
||||||
Expr *SrcExprRaw = SrcExpr.get();
|
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);
|
InitializationSequence InitSeq(Self, Entity, InitKind, SrcExprRaw);
|
||||||
|
|
||||||
// At this point of CheckStaticCast, if the destination is a reference,
|
// At this point of CheckStaticCast, if the destination is a reference,
|
||||||
|
@ -1652,7 +1655,8 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
|
||||||
if (NeedToMaterializeTemporary)
|
if (NeedToMaterializeTemporary)
|
||||||
// This is a const_cast from a class prvalue to an rvalue reference type.
|
// This is a const_cast from a class prvalue to an rvalue reference type.
|
||||||
// Materialize a temporary to store the result of the conversion.
|
// 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);
|
/*IsLValueReference*/ false);
|
||||||
|
|
||||||
return TC_Success;
|
return TC_Success;
|
||||||
|
@ -1916,7 +1920,10 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
|
||||||
switch (SrcExpr.get()->getObjectKind()) {
|
switch (SrcExpr.get()->getObjectKind()) {
|
||||||
case OK_Ordinary:
|
case OK_Ordinary:
|
||||||
break;
|
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_VectorComponent: inappropriate = "vector element"; break;
|
||||||
case OK_ObjCProperty: inappropriate = "property expression"; break;
|
case OK_ObjCProperty: inappropriate = "property expression"; break;
|
||||||
case OK_ObjCSubscript: inappropriate = "container subscripting expression";
|
case OK_ObjCSubscript: inappropriate = "container subscripting expression";
|
||||||
|
|
|
@ -5411,13 +5411,19 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
|
||||||
if (CompareReferenceRelationship(
|
if (CompareReferenceRelationship(
|
||||||
QuestionLoc, LTy, RTy, DerivedToBase,
|
QuestionLoc, LTy, RTy, DerivedToBase,
|
||||||
ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
|
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);
|
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
|
||||||
RTy = RHS.get()->getType();
|
RTy = RHS.get()->getType();
|
||||||
} else if (CompareReferenceRelationship(
|
} else if (CompareReferenceRelationship(
|
||||||
QuestionLoc, RTy, LTy, DerivedToBase,
|
QuestionLoc, RTy, LTy, DerivedToBase,
|
||||||
ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
|
ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
|
||||||
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion) {
|
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
|
||||||
|
!LHS.get()->refersToBitField() &&
|
||||||
|
!LHS.get()->refersToVectorElement()) {
|
||||||
LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
|
LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
|
||||||
LTy = LHS.get()->getType();
|
LTy = LHS.get()->getType();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3048,6 +3048,7 @@ void InitializationSequence::Step::Destroy() {
|
||||||
case SK_CastDerivedToBaseLValue:
|
case SK_CastDerivedToBaseLValue:
|
||||||
case SK_BindReference:
|
case SK_BindReference:
|
||||||
case SK_BindReferenceToTemporary:
|
case SK_BindReferenceToTemporary:
|
||||||
|
case SK_FinalCopy:
|
||||||
case SK_ExtraneousCopyToTemporary:
|
case SK_ExtraneousCopyToTemporary:
|
||||||
case SK_UserConversion:
|
case SK_UserConversion:
|
||||||
case SK_QualificationConversionRValue:
|
case SK_QualificationConversionRValue:
|
||||||
|
@ -3082,7 +3083,14 @@ void InitializationSequence::Step::Destroy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InitializationSequence::isDirectReferenceBinding() const {
|
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 {
|
bool InitializationSequence::isAmbiguous() const {
|
||||||
|
@ -3099,6 +3107,8 @@ bool InitializationSequence::isAmbiguous() const {
|
||||||
case FK_IncompatWideStringIntoWideChar:
|
case FK_IncompatWideStringIntoWideChar:
|
||||||
case FK_AddressOfOverloadFailed: // FIXME: Could do better
|
case FK_AddressOfOverloadFailed: // FIXME: Could do better
|
||||||
case FK_NonConstLValueReferenceBindingToTemporary:
|
case FK_NonConstLValueReferenceBindingToTemporary:
|
||||||
|
case FK_NonConstLValueReferenceBindingToBitfield:
|
||||||
|
case FK_NonConstLValueReferenceBindingToVectorElement:
|
||||||
case FK_NonConstLValueReferenceBindingToUnrelated:
|
case FK_NonConstLValueReferenceBindingToUnrelated:
|
||||||
case FK_RValueReferenceBindingToLValue:
|
case FK_RValueReferenceBindingToLValue:
|
||||||
case FK_ReferenceInitDropsQualifiers:
|
case FK_ReferenceInitDropsQualifiers:
|
||||||
|
@ -3167,6 +3177,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T,
|
||||||
Steps.push_back(S);
|
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) {
|
void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) {
|
||||||
Step S;
|
Step S;
|
||||||
S.Kind = SK_ExtraneousCopyToTemporary;
|
S.Kind = SK_ExtraneousCopyToTemporary;
|
||||||
|
@ -4002,12 +4019,10 @@ static void TryListInitialization(Sema &S,
|
||||||
|
|
||||||
/// \brief Try a reference initialization that involves calling a conversion
|
/// \brief Try a reference initialization that involves calling a conversion
|
||||||
/// function.
|
/// function.
|
||||||
static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
static OverloadingResult TryRefInitWithConversionFunction(
|
||||||
const InitializedEntity &Entity,
|
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
|
||||||
const InitializationKind &Kind,
|
Expr *Initializer, bool AllowRValues, bool IsLValueRef,
|
||||||
Expr *Initializer,
|
InitializationSequence &Sequence) {
|
||||||
bool AllowRValues,
|
|
||||||
InitializationSequence &Sequence) {
|
|
||||||
QualType DestType = Entity.getType();
|
QualType DestType = Entity.getType();
|
||||||
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
|
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
|
||||||
QualType T1 = cv1T1.getUnqualifiedType();
|
QualType T1 = cv1T1.getUnqualifiedType();
|
||||||
|
@ -4123,58 +4138,68 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
||||||
// use this initialization. Mark it as referenced.
|
// use this initialization. Mark it as referenced.
|
||||||
Function->setReferenced();
|
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))
|
if (isa<CXXConversionDecl>(Function))
|
||||||
T2 = Function->getReturnType();
|
cv3T3 = Function->getReturnType();
|
||||||
else
|
else
|
||||||
T2 = cv1T1;
|
cv3T3 = T1;
|
||||||
|
|
||||||
|
ExprValueKind VK = VK_RValue;
|
||||||
|
if (cv3T3->isLValueReferenceType())
|
||||||
|
VK = VK_LValue;
|
||||||
|
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.
|
// Add the user-defined conversion step.
|
||||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||||
Sequence.AddUserConversionStep(Function, Best->FoundDecl,
|
Sequence.AddUserConversionStep(Function, Best->FoundDecl, cv3T3,
|
||||||
T2.getNonLValueExprType(S.Context),
|
|
||||||
HadMultipleCandidates);
|
HadMultipleCandidates);
|
||||||
|
|
||||||
// Determine whether we need to perform derived-to-base or
|
// Determine whether we'll need to perform derived-to-base adjustments or
|
||||||
// cv-qualification adjustments.
|
// other conversions.
|
||||||
ExprValueKind VK = VK_RValue;
|
|
||||||
if (T2->isLValueReferenceType())
|
|
||||||
VK = VK_LValue;
|
|
||||||
else if (const RValueReferenceType *RRef = T2->getAs<RValueReferenceType>())
|
|
||||||
VK = RRef->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue;
|
|
||||||
|
|
||||||
bool NewDerivedToBase = false;
|
bool NewDerivedToBase = false;
|
||||||
bool NewObjCConversion = false;
|
bool NewObjCConversion = false;
|
||||||
bool NewObjCLifetimeConversion = false;
|
bool NewObjCLifetimeConversion = false;
|
||||||
Sema::ReferenceCompareResult NewRefRelationship
|
Sema::ReferenceCompareResult NewRefRelationship
|
||||||
= S.CompareReferenceRelationship(DeclLoc, T1,
|
= S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
|
||||||
T2.getNonLValueExprType(S.Context),
|
|
||||||
NewDerivedToBase, NewObjCConversion,
|
NewDerivedToBase, NewObjCConversion,
|
||||||
NewObjCLifetimeConversion);
|
NewObjCLifetimeConversion);
|
||||||
|
|
||||||
|
// Add the final conversion sequence, if necessary.
|
||||||
if (NewRefRelationship == Sema::Ref_Incompatible) {
|
if (NewRefRelationship == Sema::Ref_Incompatible) {
|
||||||
// If the type we've converted to is not reference-related to the
|
assert(!isa<CXXConstructorDecl>(Function) &&
|
||||||
// type we're looking for, then there is another conversion step
|
"should not have conversion after constructor");
|
||||||
// we need to perform to produce a temporary of the right type
|
|
||||||
// that we'll be binding to.
|
|
||||||
ImplicitConversionSequence ICS;
|
ImplicitConversionSequence ICS;
|
||||||
ICS.setStandard();
|
ICS.setStandard();
|
||||||
ICS.Standard = Best->FinalConversion;
|
ICS.Standard = Best->FinalConversion;
|
||||||
T2 = ICS.Standard.getToType(2);
|
Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2));
|
||||||
Sequence.AddConversionSequenceStep(ICS, T2);
|
|
||||||
} else if (NewDerivedToBase)
|
// Every implicit conversion results in a prvalue, except for a glvalue
|
||||||
Sequence.AddDerivedToBaseCastStep(
|
// derived-to-base conversion, which we handle below.
|
||||||
S.Context.getQualifiedType(T1,
|
cv3T3 = ICS.Standard.getToType(2);
|
||||||
T2.getNonReferenceType().getQualifiers()),
|
VK = VK_RValue;
|
||||||
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)
|
else if (NewObjCConversion)
|
||||||
Sequence.AddObjCObjectConversionStep(
|
Sequence.AddObjCObjectConversionStep(cv1T1);
|
||||||
S.Context.getQualifiedType(T1,
|
|
||||||
T2.getNonReferenceType().getQualifiers()));
|
|
||||||
|
|
||||||
if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers())
|
|
||||||
Sequence.AddQualificationConversionStep(cv1T1, VK);
|
|
||||||
|
|
||||||
Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType());
|
|
||||||
return OR_Success;
|
return OR_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4208,54 +4233,11 @@ static void TryReferenceInitialization(Sema &S,
|
||||||
T1Quals, cv2T2, T2, T2Quals, Sequence);
|
T1Quals, cv2T2, T2, T2Quals, Sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the target of reference initialization so that it has the
|
/// Determine whether an expression is a non-referenceable glvalue (one to
|
||||||
/// appropriate qualifiers and value kind.
|
/// which a reference can never bind). Attemting to bind a reference to
|
||||||
///
|
/// such a glvalue will always create a temporary.
|
||||||
/// In this case, 'x' is an 'int' lvalue, but it needs to be 'const int'.
|
static bool isNonReferenceableGLValue(Expr *E) {
|
||||||
/// \code
|
return E->refersToBitField() || E->refersToVectorElement();
|
||||||
/// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Reference initialization without resolving overloaded functions.
|
/// \brief Reference initialization without resolving overloaded functions.
|
||||||
|
@ -4293,31 +4275,28 @@ static void TryReferenceInitializationCore(Sema &S,
|
||||||
OverloadingResult ConvOvlResult = OR_Success;
|
OverloadingResult ConvOvlResult = OR_Success;
|
||||||
bool T1Function = T1->isFunctionType();
|
bool T1Function = T1->isFunctionType();
|
||||||
if (isLValueRef || T1Function) {
|
if (isLValueRef || T1Function) {
|
||||||
if (InitCategory.isLValue() &&
|
if (InitCategory.isLValue() && !isNonReferenceableGLValue(Initializer) &&
|
||||||
(RefRelationship == Sema::Ref_Compatible ||
|
(RefRelationship == Sema::Ref_Compatible ||
|
||||||
(Kind.isCStyleOrFunctionalCast() &&
|
(Kind.isCStyleOrFunctionalCast() &&
|
||||||
RefRelationship == Sema::Ref_Related))) {
|
RefRelationship == Sema::Ref_Related))) {
|
||||||
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
|
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
|
||||||
// reference-compatible with "cv2 T2," or
|
// reference-compatible with "cv2 T2," or
|
||||||
//
|
if (T1Quals != T2Quals)
|
||||||
// Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a
|
// Convert to cv1 T2. This should only add qualifiers unless this is a
|
||||||
// bit-field when we're determining whether the reference initialization
|
// c-style cast. The removal of qualifiers in that case notionally
|
||||||
// can occur. However, we do pay attention to whether it is a bit-field
|
// happens after the reference binding, but that doesn't matter.
|
||||||
// to decide whether we're actually binding to a temporary created from
|
Sequence.AddQualificationConversionStep(
|
||||||
// the bit-field.
|
S.Context.getQualifiedType(T2, T1Quals),
|
||||||
|
Initializer->getValueKind());
|
||||||
if (DerivedToBase)
|
if (DerivedToBase)
|
||||||
Sequence.AddDerivedToBaseCastStep(
|
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
|
||||||
S.Context.getQualifiedType(T1, T2Quals),
|
|
||||||
VK_LValue);
|
|
||||||
else if (ObjCConversion)
|
else if (ObjCConversion)
|
||||||
Sequence.AddObjCObjectConversionStep(
|
Sequence.AddObjCObjectConversionStep(cv1T1);
|
||||||
S.Context.getQualifiedType(T1, T2Quals));
|
|
||||||
|
|
||||||
ExprValueKind ValueKind =
|
// We only create a temporary here when binding a reference to a
|
||||||
convertQualifiersAndValueKindIfNecessary(S, Sequence, Initializer,
|
// bit-field or vector element. Those cases are't supposed to be
|
||||||
cv1T1, T1Quals, T2Quals,
|
// handled by this bullet, but the outcome is the same either way.
|
||||||
isLValueRef);
|
Sequence.AddReferenceBindingStep(cv1T1, false);
|
||||||
Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4332,7 +4311,8 @@ static void TryReferenceInitializationCore(Sema &S,
|
||||||
if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() &&
|
if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() &&
|
||||||
(isLValueRef || InitCategory.isRValue())) {
|
(isLValueRef || InitCategory.isRValue())) {
|
||||||
ConvOvlResult = TryRefInitWithConversionFunction(
|
ConvOvlResult = TryRefInitWithConversionFunction(
|
||||||
S, Entity, Kind, Initializer, /*AllowRValues*/isRValueRef, Sequence);
|
S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef,
|
||||||
|
/*IsLValueRef*/ isLValueRef, Sequence);
|
||||||
if (ConvOvlResult == OR_Success)
|
if (ConvOvlResult == OR_Success)
|
||||||
return;
|
return;
|
||||||
if (ConvOvlResult != OR_No_Viable_Function)
|
if (ConvOvlResult != OR_No_Viable_Function)
|
||||||
|
@ -4352,33 +4332,51 @@ static void TryReferenceInitializationCore(Sema &S,
|
||||||
Sequence.SetOverloadFailure(
|
Sequence.SetOverloadFailure(
|
||||||
InitializationSequence::FK_ReferenceInitOverloadFailed,
|
InitializationSequence::FK_ReferenceInitOverloadFailed,
|
||||||
ConvOvlResult);
|
ConvOvlResult);
|
||||||
else
|
else if (!InitCategory.isLValue())
|
||||||
Sequence.SetFailed(InitCategory.isLValue()
|
Sequence.SetFailed(
|
||||||
? (RefRelationship == Sema::Ref_Related
|
InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
|
||||||
? InitializationSequence::FK_ReferenceInitDropsQualifiers
|
else {
|
||||||
: InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated)
|
InitializationSequence::FailureKind FK;
|
||||||
: InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - If the initializer expression
|
// - If the initializer expression
|
||||||
// C++14-and-before:
|
// - is an
|
||||||
// - is an xvalue, class prvalue, array prvalue, or function lvalue and
|
// [<=14] xvalue (but not a bit-field), class prvalue, array prvalue, or
|
||||||
// "cv1 T1" is reference-compatible with "cv2 T2"
|
// [1z] rvalue (but not a bit-field) or
|
||||||
// C++1z:
|
// function lvalue and "cv1 T1" is reference-compatible with "cv2 T2"
|
||||||
// - is an rvalue or function lvalue and "cv1 T1" is reference-compatible
|
//
|
||||||
// with "cv2 T2"
|
// Note: functions are handled above and below rather than here...
|
||||||
// Note: functions are handled below.
|
|
||||||
if (!T1Function &&
|
if (!T1Function &&
|
||||||
(RefRelationship == Sema::Ref_Compatible ||
|
(RefRelationship == Sema::Ref_Compatible ||
|
||||||
(Kind.isCStyleOrFunctionalCast() &&
|
(Kind.isCStyleOrFunctionalCast() &&
|
||||||
RefRelationship == Sema::Ref_Related)) &&
|
RefRelationship == Sema::Ref_Related)) &&
|
||||||
(InitCategory.isXValue() ||
|
((InitCategory.isXValue() && !isNonReferenceableGLValue(Initializer)) ||
|
||||||
(InitCategory.isPRValue() &&
|
(InitCategory.isPRValue() &&
|
||||||
(S.getLangOpts().CPlusPlus1z || T2->isRecordType() ||
|
(S.getLangOpts().CPlusPlus1z || T2->isRecordType() ||
|
||||||
T2->isArrayType())))) {
|
T2->isArrayType())))) {
|
||||||
ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue : VK_RValue;
|
ExprValueKind ValueKind = InitCategory.isXValue() ? VK_XValue : VK_RValue;
|
||||||
if (InitCategory.isPRValue() && T2->isRecordType()) {
|
if (InitCategory.isPRValue() && T2->isRecordType()) {
|
||||||
// The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
|
// The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
|
||||||
// compiler the freedom to perform a copy here or bind to 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);
|
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)
|
if (DerivedToBase)
|
||||||
Sequence.AddDerivedToBaseCastStep(S.Context.getQualifiedType(T1, T2Quals),
|
Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
|
||||||
ValueKind);
|
|
||||||
else if (ObjCConversion)
|
else if (ObjCConversion)
|
||||||
Sequence.AddObjCObjectConversionStep(
|
Sequence.AddObjCObjectConversionStep(cv1T1);
|
||||||
S.Context.getQualifiedType(T1, T2Quals));
|
|
||||||
|
|
||||||
ValueKind = convertQualifiersAndValueKindIfNecessary(S, Sequence,
|
|
||||||
Initializer, cv1T1,
|
|
||||||
T1Quals, T2Quals,
|
|
||||||
isLValueRef);
|
|
||||||
|
|
||||||
Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4420,7 +4421,8 @@ static void TryReferenceInitializationCore(Sema &S,
|
||||||
if (T2->isRecordType()) {
|
if (T2->isRecordType()) {
|
||||||
if (RefRelationship == Sema::Ref_Incompatible) {
|
if (RefRelationship == Sema::Ref_Incompatible) {
|
||||||
ConvOvlResult = TryRefInitWithConversionFunction(
|
ConvOvlResult = TryRefInitWithConversionFunction(
|
||||||
S, Entity, Kind, Initializer, /*AllowRValues*/true, Sequence);
|
S, Entity, Kind, Initializer, /*AllowRValues*/ true,
|
||||||
|
/*IsLValueRef*/ isLValueRef, Sequence);
|
||||||
if (ConvOvlResult)
|
if (ConvOvlResult)
|
||||||
Sequence.SetOverloadFailure(
|
Sequence.SetOverloadFailure(
|
||||||
InitializationSequence::FK_ReferenceInitOverloadFailed,
|
InitializationSequence::FK_ReferenceInitOverloadFailed,
|
||||||
|
@ -4746,26 +4748,51 @@ static void TryUserDefinedConversion(Sema &S,
|
||||||
Sequence.AddUserConversionStep(Function, Best->FoundDecl,
|
Sequence.AddUserConversionStep(Function, Best->FoundDecl,
|
||||||
DestType.getUnqualifiedType(),
|
DestType.getUnqualifiedType(),
|
||||||
HadMultipleCandidates);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the user-defined conversion step that calls the conversion function.
|
// Add the user-defined conversion step that calls the conversion function.
|
||||||
QualType ConvType = Function->getCallResultType();
|
QualType ConvType = Function->getCallResultType();
|
||||||
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);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
|
Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
|
||||||
HadMultipleCandidates);
|
HadMultipleCandidates);
|
||||||
|
|
||||||
|
if (ConvType->getAs<RecordType>()) {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
// If the conversion following the call to the conversion function
|
// If the conversion following the call to the conversion function
|
||||||
// is interesting, add it as a separate step.
|
// is interesting, add it as a separate step.
|
||||||
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
|
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
|
/// \brief Whether the given entity, when initialized with an object
|
||||||
/// created for that initialization, requires destruction.
|
/// created for that initialization, requires destruction.
|
||||||
static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
|
static bool shouldDestroyEntity(const InitializedEntity &Entity) {
|
||||||
switch (Entity.getKind()) {
|
switch (Entity.getKind()) {
|
||||||
case InitializedEntity::EK_Result:
|
case InitializedEntity::EK_Result:
|
||||||
case InitializedEntity::EK_New:
|
case InitializedEntity::EK_New:
|
||||||
|
@ -5686,11 +5713,6 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
|
||||||
<< Entity.getMethodDecl()->getDeclName();
|
<< 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
|
/// Returns true if the parameters describe a constructor initialization of
|
||||||
/// an explicit temporary object, e.g. "Point(x, y)".
|
/// an explicit temporary object, e.g. "Point(x, y)".
|
||||||
static bool isExplicitTemporary(const InitializedEntity &Entity,
|
static bool isExplicitTemporary(const InitializedEntity &Entity,
|
||||||
|
@ -6392,6 +6414,7 @@ InitializationSequence::Perform(Sema &S,
|
||||||
case SK_CastDerivedToBaseLValue:
|
case SK_CastDerivedToBaseLValue:
|
||||||
case SK_BindReference:
|
case SK_BindReference:
|
||||||
case SK_BindReferenceToTemporary:
|
case SK_BindReferenceToTemporary:
|
||||||
|
case SK_FinalCopy:
|
||||||
case SK_ExtraneousCopyToTemporary:
|
case SK_ExtraneousCopyToTemporary:
|
||||||
case SK_UserConversion:
|
case SK_UserConversion:
|
||||||
case SK_QualificationConversionLValue:
|
case SK_QualificationConversionLValue:
|
||||||
|
@ -6479,30 +6502,6 @@ InitializationSequence::Perform(Sema &S,
|
||||||
}
|
}
|
||||||
|
|
||||||
case SK_BindReference:
|
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.
|
// Reference binding does not have any corresponding ASTs.
|
||||||
|
|
||||||
// Check exception specifications
|
// Check exception specifications
|
||||||
|
@ -6532,15 +6531,15 @@ InitializationSequence::Perform(Sema &S,
|
||||||
|
|
||||||
// Materialize the temporary into memory.
|
// Materialize the temporary into memory.
|
||||||
MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
|
MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
|
||||||
Entity.getType().getNonReferenceType(), CurInit.get(),
|
Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType());
|
||||||
Entity.getType()->isLValueReferenceType());
|
|
||||||
|
|
||||||
// Maybe lifetime-extend the temporary's subobjects to match the
|
// Maybe lifetime-extend the temporary's subobjects to match the
|
||||||
// entity's lifetime.
|
// entity's lifetime.
|
||||||
if (const InitializedEntity *ExtendingEntity =
|
if (const InitializedEntity *ExtendingEntity =
|
||||||
getEntityForTemporaryLifetimeExtension(&Entity))
|
getEntityForTemporaryLifetimeExtension(&Entity))
|
||||||
if (performReferenceExtension(MTE, ExtendingEntity))
|
if (performReferenceExtension(MTE, ExtendingEntity))
|
||||||
warnOnLifetimeExtension(S, Entity, CurInit.get(), /*IsInitializerList=*/false,
|
warnOnLifetimeExtension(S, Entity, CurInit.get(),
|
||||||
|
/*IsInitializerList=*/false,
|
||||||
ExtendingEntity->getDecl());
|
ExtendingEntity->getDecl());
|
||||||
|
|
||||||
// If we're binding to an Objective-C object that has lifetime, we
|
// If we're binding to an Objective-C object that has lifetime, we
|
||||||
|
@ -6557,6 +6556,18 @@ InitializationSequence::Perform(Sema &S,
|
||||||
break;
|
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:
|
case SK_ExtraneousCopyToTemporary:
|
||||||
CurInit = CopyObject(S, Step->Type, Entity, CurInit,
|
CurInit = CopyObject(S, Step->Type, Entity, CurInit,
|
||||||
/*IsExtraneousCopy=*/true);
|
/*IsExtraneousCopy=*/true);
|
||||||
|
@ -6566,7 +6577,6 @@ InitializationSequence::Perform(Sema &S,
|
||||||
// We have a user-defined conversion that invokes either a constructor
|
// We have a user-defined conversion that invokes either a constructor
|
||||||
// or a conversion function.
|
// or a conversion function.
|
||||||
CastKind CastKind;
|
CastKind CastKind;
|
||||||
bool IsCopy = false;
|
|
||||||
FunctionDecl *Fn = Step->Function.Function;
|
FunctionDecl *Fn = Step->Function.Function;
|
||||||
DeclAccessPair FoundFn = Step->Function.FoundDecl;
|
DeclAccessPair FoundFn = Step->Function.FoundDecl;
|
||||||
bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
|
bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
|
||||||
|
@ -6575,7 +6585,6 @@ InitializationSequence::Perform(Sema &S,
|
||||||
// Build a call to the selected constructor.
|
// Build a call to the selected constructor.
|
||||||
SmallVector<Expr*, 8> ConstructorArgs;
|
SmallVector<Expr*, 8> ConstructorArgs;
|
||||||
SourceLocation Loc = CurInit.get()->getLocStart();
|
SourceLocation Loc = CurInit.get()->getLocStart();
|
||||||
CurInit.get(); // Ownership transferred into MultiExprArg, below.
|
|
||||||
|
|
||||||
// Determine the arguments required to actually perform the constructor
|
// Determine the arguments required to actually perform the constructor
|
||||||
// call.
|
// call.
|
||||||
|
@ -6604,11 +6613,6 @@ InitializationSequence::Perform(Sema &S,
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
CastKind = CK_ConstructorConversion;
|
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;
|
CreatedObject = true;
|
||||||
} else {
|
} else {
|
||||||
// Build a call to the conversion function.
|
// Build a call to the conversion function.
|
||||||
|
@ -6621,48 +6625,35 @@ InitializationSequence::Perform(Sema &S,
|
||||||
// FIXME: Should we move this initialization into a separate
|
// FIXME: Should we move this initialization into a separate
|
||||||
// derived-to-base conversion? I believe the answer is "no", because
|
// 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.
|
// we don't want to turn off access control here for c-style casts.
|
||||||
ExprResult CurInitExprRes =
|
CurInit = S.PerformObjectArgumentInitialization(CurInit.get(),
|
||||||
S.PerformObjectArgumentInitialization(CurInit.get(),
|
/*Qualifier=*/nullptr,
|
||||||
/*Qualifier=*/nullptr,
|
FoundFn, Conversion);
|
||||||
FoundFn, Conversion);
|
if (CurInit.isInvalid())
|
||||||
if(CurInitExprRes.isInvalid())
|
|
||||||
return ExprError();
|
return ExprError();
|
||||||
CurInit = CurInitExprRes;
|
|
||||||
|
|
||||||
// Build the actual call to the conversion function.
|
// Build the actual call to the conversion function.
|
||||||
CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
|
CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
|
||||||
HadMultipleCandidates);
|
HadMultipleCandidates);
|
||||||
if (CurInit.isInvalid() || !CurInit.get())
|
if (CurInit.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
CastKind = CK_UserDefinedConversion;
|
CastKind = CK_UserDefinedConversion;
|
||||||
|
|
||||||
CreatedObject = Conversion->getReturnType()->isRecordType();
|
CreatedObject = Conversion->getReturnType()->isRecordType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++14 and before:
|
CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(),
|
||||||
// - if the function is a constructor, the call initializes a temporary
|
CastKind, CurInit.get(), nullptr,
|
||||||
// of the cv-unqualified version of the destination type [...]
|
CurInit.get()->getValueKind());
|
||||||
// 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)) {
|
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();
|
QualType T = CurInit.get()->getType();
|
||||||
if (const RecordType *Record = T->getAs<RecordType>()) {
|
if (const RecordType *Record = T->getAs<RecordType>()) {
|
||||||
CXXDestructorDecl *Destructor
|
CXXDestructorDecl *Destructor
|
||||||
|
@ -6674,15 +6665,6 @@ InitializationSequence::Perform(Sema &S,
|
||||||
return ExprError();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7350,6 +7332,25 @@ bool InitializationSequence::Diagnose(Sema &S,
|
||||||
<< Args[0]->getSourceRange();
|
<< Args[0]->getSourceRange();
|
||||||
break;
|
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:
|
case FK_RValueReferenceBindingToLValue:
|
||||||
S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
|
S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
|
||||||
<< DestType.getNonReferenceType() << Args[0]->getType()
|
<< DestType.getNonReferenceType() << Args[0]->getType()
|
||||||
|
@ -7647,6 +7648,14 @@ void InitializationSequence::dump(raw_ostream &OS) const {
|
||||||
OS << "non-const lvalue reference bound to temporary";
|
OS << "non-const lvalue reference bound to temporary";
|
||||||
break;
|
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:
|
case FK_NonConstLValueReferenceBindingToUnrelated:
|
||||||
OS << "non-const lvalue reference bound to unrelated type";
|
OS << "non-const lvalue reference bound to unrelated type";
|
||||||
break;
|
break;
|
||||||
|
@ -7743,15 +7752,15 @@ void InitializationSequence::dump(raw_ostream &OS) const {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SK_CastDerivedToBaseRValue:
|
case SK_CastDerivedToBaseRValue:
|
||||||
OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")";
|
OS << "derived-to-base (rvalue)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SK_CastDerivedToBaseXValue:
|
case SK_CastDerivedToBaseXValue:
|
||||||
OS << "derived-to-base case (xvalue" << S->Type.getAsString() << ")";
|
OS << "derived-to-base (xvalue)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SK_CastDerivedToBaseLValue:
|
case SK_CastDerivedToBaseLValue:
|
||||||
OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")";
|
OS << "derived-to-base (lvalue)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SK_BindReference:
|
case SK_BindReference:
|
||||||
|
@ -7762,6 +7771,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
|
||||||
OS << "bind reference to a temporary";
|
OS << "bind reference to a temporary";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SK_FinalCopy:
|
||||||
|
OS << "final copy in class direct-initialization";
|
||||||
|
break;
|
||||||
|
|
||||||
case SK_ExtraneousCopyToTemporary:
|
case SK_ExtraneousCopyToTemporary:
|
||||||
OS << "extraneous C++03 copy to temporary";
|
OS << "extraneous C++03 copy to temporary";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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
|
// Type is an aggregate, argument is an init list. At this point it comes
|
||||||
// down to checking whether the initialization works.
|
// down to checking whether the initialization works.
|
||||||
// FIXME: Find out whether this parameter is consumed or not.
|
// 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 Entity =
|
||||||
InitializedEntity::InitializeParameter(S.Context, ToType,
|
InitializedEntity::InitializeParameter(S.Context, ToType,
|
||||||
/*Consumed=*/false);
|
/*Consumed=*/false);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
|
||||||
|
|
||||||
// CHECK: example0
|
// CHECK-LABEL: example0
|
||||||
void example0() {
|
void example0() {
|
||||||
double d = 2.0;
|
double d = 2.0;
|
||||||
// CHECK: VarDecl{{.*}}rd 'double &'
|
// CHECK: VarDecl{{.*}}rd 'double &'
|
||||||
|
@ -14,14 +14,15 @@ void example0() {
|
||||||
struct A { };
|
struct A { };
|
||||||
struct B : A { } b;
|
struct B : A { } b;
|
||||||
|
|
||||||
// CHECK: example1
|
// CHECK-LABEL: example1
|
||||||
void example1() {
|
void example1() {
|
||||||
// CHECK: VarDecl{{.*}}ra 'struct A &'
|
// CHECK: VarDecl{{.*}}ra 'struct A &'
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
|
// CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
|
||||||
A &ra = b;
|
A &ra = b;
|
||||||
// CHECK: VarDecl{{.*}}rca 'const struct A &'
|
// CHECK: VarDecl{{.*}}rca 'const struct A &'
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <NoOp>
|
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
|
// CHECK-NOT: MaterializeTemporaryExpr
|
||||||
|
// CHECK: ImplicitCastExpr{{.*}}'const struct B' lvalue <NoOp>
|
||||||
const A& rca = b;
|
const A& rca = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,21 +32,23 @@ struct X {
|
||||||
operator B();
|
operator B();
|
||||||
} x;
|
} x;
|
||||||
|
|
||||||
// CHECK: example2
|
// CHECK-LABEL: example2
|
||||||
void example2() {
|
void example2() {
|
||||||
// CHECK: VarDecl{{.*}}rca 'const struct A &'
|
// CHECK: VarDecl{{.*}}rca 'const struct A &'
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
|
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
|
// CHECK: MaterializeTemporaryExpr{{.*}}'const struct B'
|
||||||
|
// CHECK: ImplicitCastExpr{{.*}}'const struct B' <NoOp>
|
||||||
// CHECK: CallExpr{{.*}}B
|
// CHECK: CallExpr{{.*}}B
|
||||||
const A &rca = f();
|
const A &rca = f();
|
||||||
// CHECK: VarDecl{{.*}}r 'const struct A &'
|
// CHECK: VarDecl{{.*}}r 'const struct A &'
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
|
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
|
||||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
|
// CHECK: MaterializeTemporaryExpr{{.*}}'const struct B'
|
||||||
|
// CHECK: ImplicitCastExpr{{.*}}'const struct B' <NoOp>
|
||||||
// CHECK: CXXMemberCallExpr{{.*}}'struct B'
|
// CHECK: CXXMemberCallExpr{{.*}}'struct B'
|
||||||
const A& r = x;
|
const A& r = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: example3
|
// CHECK-LABEL: example3
|
||||||
void example3() {
|
void example3() {
|
||||||
// CHECK: VarDecl{{.*}}rcd2 'const double &'
|
// CHECK: VarDecl{{.*}}rcd2 'const double &'
|
||||||
// CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>
|
// CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace PR6066 {
|
||||||
|
|
||||||
namespace test3 {
|
namespace test3 {
|
||||||
struct A {
|
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 bitY : 4; // expected-note {{bit-field is declared here}}
|
||||||
unsigned var;
|
unsigned var;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ namespace test3 {
|
||||||
|
|
||||||
void test(A *a) {
|
void test(A *a) {
|
||||||
unsigned &t0 = a->bitX; // expected-error {{non-const reference cannot bind to bit-field 'bitX'}}
|
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 &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 &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}}
|
unsigned &t4 = (a->var ? a->bitX : a->bitY); // expected-error {{non-const reference cannot bind to bit-field}}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
// 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
|
// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||||
|
|
||||||
// expected-no-diagnostics
|
|
||||||
|
|
||||||
namespace dr1213 { // dr1213: 4.0
|
namespace dr1213 { // dr1213: 4.0
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
using T = int[3];
|
using T = int[3];
|
||||||
|
@ -27,3 +25,29 @@ struct Derived : Base {
|
||||||
virtual Incomplete *meow();
|
virtual Incomplete *meow();
|
||||||
};
|
};
|
||||||
} // dr1250
|
} // 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@-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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,6 +386,18 @@ namespace FakeInitList {
|
||||||
constexpr init_list_2_init_list_3_ints ils = { { { { 1, 2, 3 } }, { { 4, 5, 6 } } } };
|
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) {
|
constexpr int strcmp_ce(const char *p, const char *q) {
|
||||||
|
|
|
@ -39,3 +39,8 @@ namespace NoexceptFunctionTypes {
|
||||||
static_assert(A<int>().g());
|
static_assert(A<int>().g());
|
||||||
static_assert(A<int>()());
|
static_assert(A<int>()());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Cxx17CD_NB_GB19 {
|
||||||
|
const int &r = 0;
|
||||||
|
constexpr int n = r;
|
||||||
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace PR14838 {
|
||||||
struct thing {};
|
struct thing {};
|
||||||
struct another {
|
struct another {
|
||||||
another() : r(thing()) {}
|
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}}
|
// expected-warning@-2 {{binding reference member 'r' to a temporary value}}
|
||||||
const function &r; // expected-note {{reference member declared here}}
|
const function &r; // expected-note {{reference member declared here}}
|
||||||
} af;
|
} af;
|
||||||
|
|
|
@ -16,7 +16,7 @@ void *operator new(size_t, const noncopyable&);
|
||||||
void *q = new (nc) int[4]; // expected-error {{calling a private constructor}}
|
void *q = new (nc) int[4]; // expected-error {{calling a private constructor}}
|
||||||
|
|
||||||
struct bitfield { int n : 3; } bf; // expected-note {{here}}
|
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 *operator new(size_t, const int &);
|
||||||
void *r = new (bf.n) int[4]; // expected-error {{non-const reference cannot bind to bit-field}}
|
void *r = new (bf.n) int[4]; // expected-error {{non-const reference cannot bind to bit-field}}
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ void const_arrays() {
|
||||||
|
|
||||||
namespace PR9564 {
|
namespace PR9564 {
|
||||||
struct a { int a : 10; }; a x;
|
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;
|
__attribute((ext_vector_type(4))) typedef float v4;
|
||||||
float& w(v4 &a) { return reinterpret_cast<float&>(a[1]); } // expected-error {{not allowed}}
|
float& w(v4 &a) { return reinterpret_cast<float&>(a[1]); } // expected-error {{not allowed}}
|
||||||
|
|
Loading…
Reference in New Issue