Refactor CompareReferenceRelationship and its callers in preparation for

implementing the resolution of CWG2352.

No functionality change, except that we now convert the referent of a
reference binding to the underlying type of the reference in more cases;
we used to happen to preserve the type sugar from the referent if the
only type change was in the cv-qualifiers.

This exposed a bug in how we generate code for trivial assignment
operators: if the type sugar (particularly the may_alias attribute)
got lost during reference binding, we'd use the "wrong" TBAA information
for the load during the assignment.
This commit is contained in:
Richard Smith 2019-12-18 14:01:40 -08:00
parent a6d57a8cd4
commit 3ced23976a
8 changed files with 161 additions and 167 deletions

View File

@ -31,6 +31,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/BitmaskEnum.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/OpenMPKinds.h"
@ -10703,11 +10704,26 @@ public:
Ref_Compatible
};
// Fake up a scoped enumeration that still contextually converts to bool.
struct ReferenceConversionsScope {
/// The conversions that would be performed on an lvalue of type T2 when
/// binding a reference of type T1 to it, as determined when evaluating
/// whether T1 is reference-compatible with T2.
enum ReferenceConversions {
Qualification = 0x1,
Function = 0x2,
DerivedToBase = 0x4,
ObjC = 0x8,
ObjCLifetime = 0x10,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime)
};
};
using ReferenceConversions = ReferenceConversionsScope::ReferenceConversions;
ReferenceCompareResult
CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2,
bool &DerivedToBase, bool &ObjCConversion,
bool &ObjCLifetimeConversion,
bool &FunctionConversion);
ReferenceConversions *Conv = nullptr);
ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
Expr *CastExpr, CastKind &CastKind,

View File

@ -241,16 +241,28 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
}
}
bool TrivialForCodegen =
MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion());
bool TrivialAssignment =
TrivialForCodegen &&
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
!MD->getParent()->mayInsertExtraPadding();
// C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
// operator before the LHS.
CallArgList RtlArgStorage;
CallArgList *RtlArgs = nullptr;
LValue TrivialAssignmentRHS;
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
if (OCE->isAssignmentOp()) {
RtlArgs = &RtlArgStorage;
EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
/*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
if (TrivialAssignment) {
TrivialAssignmentRHS = EmitLValue(CE->getArg(1));
} else {
RtlArgs = &RtlArgStorage;
EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
/*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
}
}
}
@ -281,22 +293,25 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
return RValue::get(nullptr);
}
if (MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion())) {
if (isa<CXXDestructorDecl>(MD)) return RValue::get(nullptr);
if (!MD->getParent()->mayInsertExtraPadding()) {
if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
// We don't like to generate the trivial copy/move assignment operator
// when it isn't necessary; just produce the proper effect here.
LValue RHS = isa<CXXOperatorCallExpr>(CE)
? MakeNaturalAlignAddrLValue(
(*RtlArgs)[0].getRValue(*this).getScalarVal(),
(*(CE->arg_begin() + 1))->getType())
: EmitLValue(*CE->arg_begin());
EmitAggregateAssign(This, RHS, CE->getType());
return RValue::get(This.getPointer(*this));
}
llvm_unreachable("unknown trivial member function");
if (TrivialForCodegen) {
if (isa<CXXDestructorDecl>(MD))
return RValue::get(nullptr);
if (TrivialAssignment) {
// We don't like to generate the trivial copy/move assignment operator
// when it isn't necessary; just produce the proper effect here.
// It's important that we use the result of EmitLValue here rather than
// emitting call arguments, in order to preserve TBAA information from
// the RHS.
LValue RHS = isa<CXXOperatorCallExpr>(CE)
? TrivialAssignmentRHS
: EmitLValue(*CE->arg_begin());
EmitAggregateAssign(This, RHS, CE->getType());
return RValue::get(This.getPointer(*this));
}
assert(MD->getParent()->mayInsertExtraPadding() &&
"unknown trivial member function");
}
// Compute the function type we're calling.

View File

@ -1306,10 +1306,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
// Because we try the reference downcast before this function, from now on
// this is the only cast possibility, so we issue an error if we fail now.
// FIXME: Should allow casting away constness if CStyle.
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
bool FunctionConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@ -1317,9 +1313,9 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
ToType = ToType.getUnqualifiedType();
}
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
ObjCLifetimeConversion, FunctionConversion);
SrcExpr->getBeginLoc(), ToType, FromType, &RefConv);
if (RefResult != Sema::Ref_Compatible) {
if (CStyle || RefResult == Sema::Ref_Incompatible)
return TC_NotApplicable;
@ -1331,7 +1327,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
return TC_Failed;
}
if (DerivedToBase) {
if (RefConv & Sema::ReferenceConversions::DerivedToBase) {
Kind = CK_DerivedToBase;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);

View File

@ -5862,29 +5862,29 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// FIXME:
// Resolving a defect in P0012R1: we extend this to cover all cases where
// one of the operands is reference-compatible with the other, in order
// to support conditionals between functions differing in noexcept.
// to support conditionals between functions differing in noexcept. This
// will similarly cover difference in array bounds after P0388R4.
ExprValueKind LVK = LHS.get()->getValueKind();
ExprValueKind RVK = RHS.get()->getValueKind();
if (!Context.hasSameType(LTy, RTy) &&
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
FunctionConversion;
if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
ObjCConversion, ObjCLifetimeConversion,
FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
const ReferenceConversions AllowedConversions =
ReferenceConversions::Qualification | ReferenceConversions::Function;
ReferenceConversions RefConv;
if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
Ref_Compatible &&
!(RefConv & ~AllowedConversions) &&
// [...] 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,
FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
} else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) ==
Ref_Compatible &&
!(RefConv & ~AllowedConversions) &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);

View File

@ -4229,10 +4229,8 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
dummy2, dummy3, dummy4);
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@ -4469,18 +4467,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
bool FunctionConversion;
assert(!S.CompareReferenceRelationship(
Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
ObjCLifetimeConversion, FunctionConversion) &&
assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
(void)ObjCLifetimeConversion;
(void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@ -4604,14 +4592,9 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Determine whether we'll need to perform derived-to-base adjustments or
// other conversions.
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
bool NewObjCLifetimeConversion = false;
bool NewFunctionConversion = false;
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult NewRefRelationship =
S.CompareReferenceRelationship(
DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
NewObjCLifetimeConversion, NewFunctionConversion);
S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, &RefConv);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@ -4641,12 +4624,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue);
VK = IsLValueRef ? VK_LValue : VK_XValue;
if (NewDerivedToBase)
if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
else if (NewObjCConversion)
else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
else if (NewFunctionConversion)
else if (RefConv & Sema::ReferenceConversions::Function)
Sequence.AddQualificationConversionStep(cv1T1, VK);
else if (RefConv & Sema::ReferenceConversions::Qualification) {
if (!S.Context.hasSameType(cv1T4, cv1T1))
Sequence.AddQualificationConversionStep(cv1T1, VK);
}
return OR_Success;
}
@ -4700,17 +4687,15 @@ static void TryReferenceInitializationCore(Sema &S,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
SourceLocation DeclLoc = Initializer->getBeginLoc();
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
ObjCLifetimeConversion, FunctionConversion);
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, &RefConv);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@ -4730,19 +4715,25 @@ static void TryReferenceInitializationCore(Sema &S,
RefRelationship == Sema::Ref_Related))) {
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
// reference-compatible with "cv2 T2," or
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(cv1T1, VK_LValue);
else if (ObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
else if (FunctionConversion)
Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
if (RefConv & (Sema::ReferenceConversions::DerivedToBase |
Sema::ReferenceConversions::ObjC)) {
// If we're converting the pointee, add any qualifiers first;
// these qualifiers must all be top-level, so just convert to "cv1 T2".
if (RefConv & (Sema::ReferenceConversions::Qualification))
Sequence.AddQualificationConversionStep(
S.Context.getQualifiedType(T2, T1Quals),
Initializer->getValueKind());
if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
else
Sequence.AddObjCObjectConversionStep(cv1T1);
} else if (RefConv & (Sema::ReferenceConversions::Qualification |
Sema::ReferenceConversions::Function)) {
// Perform a (possibly multi-level) qualification conversion.
// FIXME: Should we use a different step kind for function conversions?
Sequence.AddQualificationConversionStep(cv1T1,
Initializer->getValueKind());
}
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
@ -4873,14 +4864,19 @@ static void TryReferenceInitializationCore(Sema &S,
T4Quals.addAddressSpace(T1Quals.getAddressSpace());
QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals);
Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
cv1T4 = cv1T4WithAS;
}
// In any case, the reference is bound to the resulting glvalue (or to
// an appropriate base class subobject).
if (DerivedToBase)
if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
else if (ObjCConversion)
else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
else if (RefConv & Sema::ReferenceConversions::Qualification) {
if (!S.Context.hasSameType(cv1T4, cv1T1))
Sequence.AddQualificationConversionStep(cv1T1, ValueKind);
}
return;
}

View File

@ -4412,10 +4412,7 @@ static bool isTypeValid(QualType T) {
Sema::ReferenceCompareResult
Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool &DerivedToBase,
bool &ObjCConversion,
bool &ObjCLifetimeConversion,
bool &FunctionConversion) {
ReferenceConversions *ConvOut) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@ -4426,24 +4423,25 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
ReferenceConversions ConvTmp;
ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
Conv = ReferenceConversions();
// C++ [dcl.init.ref]p4:
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
// reference-related to "cv2 T2" if T1 is the same type as T2, or
// T1 is a base class of T2.
DerivedToBase = false;
ObjCConversion = false;
ObjCLifetimeConversion = false;
QualType ConvertedT2;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (isCompleteType(Loc, OrigT2) &&
isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
IsDerivedFrom(Loc, UnqualT2, UnqualT1))
DerivedToBase = true;
Conv |= ReferenceConversions::DerivedToBase;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
ObjCConversion = true;
Conv |= ReferenceConversions::ObjC;
else if (UnqualT2->isFunctionType() &&
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
// C++1z [dcl.init.ref]p4:
@ -4452,7 +4450,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
//
// We extend this to also apply to 'noreturn', so allow any function
// conversion between function types.
FunctionConversion = true;
Conv |= ReferenceConversions::Function;
return Ref_Compatible;
} else
return Ref_Incompatible;
@ -4482,7 +4480,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
ObjCLifetimeConversion = true;
Conv |= ReferenceConversions::ObjCLifetime;
T1Quals.removeObjCLifetime();
T2Quals.removeObjCLifetime();
@ -4492,6 +4490,9 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
T1Quals.removeUnaligned();
T2Quals.removeUnaligned();
if (T1Quals != T2Quals)
Conv |= ReferenceConversions::Qualification;
if (T1Quals.compatiblyIncludes(T2Quals))
return Ref_Compatible;
else
@ -4532,11 +4533,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
continue;
if (AllowRvalues) {
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
bool FunctionConversion = false;
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
@ -4552,9 +4548,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
Conv->getConversionType()
.getNonReferenceType()
.getUnqualifiedType(),
DeclType.getNonReferenceType().getUnqualifiedType(),
DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
FunctionConversion) == Sema::Ref_Incompatible)
DeclType.getNonReferenceType().getUnqualifiedType()) ==
Sema::Ref_Incompatible)
continue;
} else {
// If the conversion function doesn't return a reference type,
@ -4655,14 +4650,36 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// Compute some basic properties of the types and the initializer.
bool isRValRef = DeclType->isRValueReferenceType();
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
bool FunctionConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
FunctionConversion);
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);
auto SetAsReferenceBinding = [&](bool BindsDirectly) {
ICS.setStandard();
ICS.Standard.First = ICK_Identity;
ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
? ICK_Derived_To_Base
: (RefConv & Sema::ReferenceConversions::ObjC)
? ICK_Compatible_Conversion
: ICK_Identity;
ICS.Standard.Third = ICK_Identity;
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
ICS.Standard.setToType(0, T2);
ICS.Standard.setToType(1, T1);
ICS.Standard.setToType(2, T1);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = BindsDirectly;
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding =
(RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0;
ICS.Standard.CopyConstructor = nullptr;
ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
};
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@ -4682,25 +4699,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// has a type that is a derived class of the parameter type,
// in which case the implicit conversion sequence is a
// derived-to-base Conversion (13.3.3.1).
ICS.setStandard();
ICS.Standard.First = ICK_Identity;
ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
: ObjCConversion? ICK_Compatible_Conversion
: ICK_Identity;
ICS.Standard.Third = ICK_Identity;
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
ICS.Standard.setToType(0, T2);
ICS.Standard.setToType(1, T1);
ICS.Standard.setToType(2, T1);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = true;
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = false;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = nullptr;
ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
SetAsReferenceBinding(/*BindsDirectly=*/true);
// Nothing more to do: the inaccessibility/ambiguity check for
// derived-to-base conversions is suppressed when we're
@ -4738,34 +4737,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
if (RefRelationship == Sema::Ref_Compatible &&
(InitCategory.isXValue() ||
(InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
(InitCategory.isPRValue() &&
(T2->isRecordType() || T2->isArrayType())) ||
(InitCategory.isLValue() && T2->isFunctionType()))) {
ICS.setStandard();
ICS.Standard.First = ICK_Identity;
ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
: ObjCConversion? ICK_Compatible_Conversion
: ICK_Identity;
ICS.Standard.Third = ICK_Identity;
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
ICS.Standard.setToType(0, T2);
ICS.Standard.setToType(1, T1);
ICS.Standard.setToType(2, T1);
ICS.Standard.ReferenceBinding = true;
// In C++0x, this is always a direct binding. In C++98/03, it's a direct
// In C++11, this is always a direct binding. In C++98/03, it's a direct
// binding unless we're binding to a class prvalue.
// Note: Although xvalues wouldn't normally show up in C++98/03 code, we
// allow the use of rvalue references in C++98/03 for the benefit of
// standard library implementors; therefore, we need the xvalue check here.
ICS.Standard.DirectBinding =
S.getLangOpts().CPlusPlus11 ||
!(InitCategory.isPRValue() || T2->isRecordType());
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = nullptr;
ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
SetAsReferenceBinding(/*BindsDirectly=*/S.getLangOpts().CPlusPlus11 ||
!(InitCategory.isPRValue() || T2->isRecordType()));
return ICS;
}
@ -5084,13 +5065,8 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
}
// Compute some basic properties of the types and the initializer.
bool dummy1 = false;
bool dummy2 = false;
bool dummy3 = false;
bool dummy4 = false;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
dummy2, dummy3, dummy4);
S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),

View File

@ -7991,7 +7991,6 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "desugaredQualType": "const NS::X",
// CHECK-NEXT: "qualType": "const NS::X"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "lvalue",
@ -8148,7 +8147,6 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "desugaredQualType": "const NS::X",
// CHECK-NEXT: "qualType": "const NS::X"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "lvalue",
@ -8430,7 +8428,6 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "desugaredQualType": "const NS::X",
// CHECK-NEXT: "qualType": "const NS::X"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "lvalue",
@ -8758,7 +8755,6 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "desugaredQualType": "const NS::X",
// CHECK-NEXT: "qualType": "const NS::X"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "lvalue",
@ -8915,7 +8911,6 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "desugaredQualType": "const NS::X",
// CHECK-NEXT: "qualType": "const NS::X"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "lvalue",

View File

@ -196,7 +196,7 @@ inline namespace InlineNS {}
// CHECK: TemplateRef=Specialization:66:8 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: CallExpr=Specialization:66:8 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: VarDecl=autoTemplRefParam:72:6 (Definition) [type=Specialization<Specialization<bool> &>] [typekind=Auto] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Unexposed] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=const Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Record] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A<void>] [typekind=Unexposed]] [canonicaltype=A<void>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0]
// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Record]