mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
Tweak Sema::CheckReferenceInit so that it (optionally) computes an
ImplicitConversionSequence and, when doing so, following the specific rules of [over.best.ics]. The computation of the implicit conversion sequences implements C++ [over.ics.ref], but we do not (yet) have ranking for implicit conversion sequences that use reference binding. llvm-svn: 58357
This commit is contained in:
parent
cfa9d8e9a0
commit
786ab2119f
@ -1139,10 +1139,11 @@ private:
|
||||
Ref_Compatible
|
||||
};
|
||||
|
||||
ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2);
|
||||
ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2,
|
||||
bool& DerivedToBase);
|
||||
|
||||
bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
|
||||
bool Complain = true);
|
||||
ImplicitConversionSequence *ICS = 0);
|
||||
|
||||
/// CheckCastTypes - Check type constraints for casting between types.
|
||||
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
|
||||
|
@ -688,7 +688,8 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc,
|
||||
/// type, and the first type (T1) is the pointee type of the reference
|
||||
/// type being initialized.
|
||||
Sema::ReferenceCompareResult
|
||||
Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
|
||||
Sema::CompareReferenceRelationship(QualType T1, QualType T2,
|
||||
bool& DerivedToBase) {
|
||||
assert(!T1->isReferenceType() && "T1 must be the pointee type of the reference type");
|
||||
assert(!T2->isReferenceType() && "T2 cannot be a reference type");
|
||||
|
||||
@ -701,10 +702,11 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
|
||||
// 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.
|
||||
//
|
||||
// If neither of these conditions is met, the two types are not
|
||||
// reference related at all.
|
||||
if (UnqualT1 != UnqualT2 && !IsDerivedFrom(UnqualT2, UnqualT1))
|
||||
if (UnqualT1 == UnqualT2)
|
||||
DerivedToBase = false;
|
||||
else if (IsDerivedFrom(UnqualT2, UnqualT1))
|
||||
DerivedToBase = true;
|
||||
else
|
||||
return Ref_Incompatible;
|
||||
|
||||
// At this point, we know that T1 and T2 are reference-related (at
|
||||
@ -731,17 +733,27 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
|
||||
/// list), and DeclType is the type of the declaration. When Complain
|
||||
/// is true, this routine will produce diagnostics (and return true)
|
||||
/// when the declaration cannot be initialized with the given
|
||||
/// initializer. When Complain is false, this routine will return true
|
||||
/// when the initialization cannot be performed, but will not produce
|
||||
/// any diagnostics or alter Init.
|
||||
bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
/// initializer. When ICS is non-null, this routine will compute the
|
||||
/// implicit conversion sequence according to C++ [over.ics.ref] and
|
||||
/// will not produce any diagnostics; when ICS is null, it will emit
|
||||
/// diagnostics when any errors are found.
|
||||
bool
|
||||
Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
|
||||
ImplicitConversionSequence *ICS) {
|
||||
assert(DeclType->isReferenceType() && "Reference init needs a reference");
|
||||
|
||||
QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
|
||||
QualType T2 = Init->getType();
|
||||
|
||||
// Compute some basic properties of the types and the initializer.
|
||||
bool DerivedToBase = false;
|
||||
Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);
|
||||
ReferenceCompareResult RefRelationship = CompareReferenceRelationship(T1, T2);
|
||||
ReferenceCompareResult RefRelationship
|
||||
= CompareReferenceRelationship(T1, T2, DerivedToBase);
|
||||
|
||||
// Most paths end in a failed conversion.
|
||||
if (ICS)
|
||||
ICS->ConversionKind = ImplicitConversionSequence::BadConversion;
|
||||
|
||||
// C++ [dcl.init.ref]p5:
|
||||
// A reference to type “cv1 T1” is initialized by an expression
|
||||
@ -752,11 +764,37 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
bool BindsDirectly = false;
|
||||
// -- is an lvalue (but is not a bit-field), and “cv1 T1” is
|
||||
// reference-compatible with “cv2 T2,” or
|
||||
if (InitLvalue == Expr::LV_Valid && !Init->isBitField() &&
|
||||
RefRelationship >= Ref_Compatible) {
|
||||
//
|
||||
// Note that the bit-field check is skipped if we are just computing
|
||||
// the implicit conversion sequence (C++ [over.best.ics]p2).
|
||||
if (InitLvalue == Expr::LV_Valid && (ICS || !Init->isBitField()) &&
|
||||
RefRelationship >= Ref_Compatible_With_Added_Qualification) {
|
||||
BindsDirectly = true;
|
||||
|
||||
if (!Complain) {
|
||||
if (ICS) {
|
||||
// C++ [over.ics.ref]p1:
|
||||
// When a parameter of reference type binds directly (8.5.3)
|
||||
// to an argument expression, the implicit conversion sequence
|
||||
// is the identity conversion, unless the argument expression
|
||||
// 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->ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||
ICS->Standard.First = ICK_Identity;
|
||||
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
|
||||
ICS->Standard.Third = ICK_Identity;
|
||||
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
|
||||
ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
|
||||
ICS->ReferenceBinding = true;
|
||||
ICS->DirectBinding = true;
|
||||
|
||||
// Nothing more to do: the inaccessibility/ambiguity check for
|
||||
// derived-to-base conversions is suppressed when we're
|
||||
// computing the implicit conversion sequence (C++
|
||||
// [over.best.ics]p2).
|
||||
return false;
|
||||
} else {
|
||||
// Perform the conversion.
|
||||
// FIXME: Binding to a subobject of the lvalue is going to require
|
||||
// more AST annotation than this.
|
||||
ImpCastExprToType(Init, T1);
|
||||
@ -770,7 +808,7 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
// applicable conversion functions (13.3.1.6) and choosing
|
||||
// the best one through overload resolution (13.3)),
|
||||
// FIXME: Implement this second bullet, once we have conversion
|
||||
// functions.
|
||||
// functions. Also remember C++ [over.ics.ref]p1, second part.
|
||||
|
||||
if (BindsDirectly) {
|
||||
// C++ [dcl.init.ref]p4:
|
||||
@ -785,20 +823,18 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
// complain about errors, because we should not be checking for
|
||||
// ambiguity (or inaccessibility) unless the reference binding
|
||||
// actually happens.
|
||||
if (Complain &&
|
||||
(Context.getCanonicalType(T1).getUnqualifiedType()
|
||||
!= Context.getCanonicalType(T2).getUnqualifiedType()) &&
|
||||
CheckDerivedToBaseConversion(T2, T1, Init->getSourceRange().getBegin(),
|
||||
Init->getSourceRange()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
if (DerivedToBase)
|
||||
return CheckDerivedToBaseConversion(T2, T1,
|
||||
Init->getSourceRange().getBegin(),
|
||||
Init->getSourceRange());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// -- Otherwise, the reference shall be to a non-volatile const
|
||||
// type (i.e., cv1 shall be const).
|
||||
if (T1.getCVRQualifiers() != QualType::Const) {
|
||||
if (Complain)
|
||||
if (!ICS)
|
||||
Diag(Init->getSourceRange().getBegin(),
|
||||
diag::err_not_reference_to_const_init,
|
||||
T1.getAsString(),
|
||||
@ -832,8 +868,17 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
// a temporary in this case. FIXME: We will, however, have to check
|
||||
// for the presence of a copy constructor in C++98/03 mode.
|
||||
if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
|
||||
RefRelationship >= Ref_Compatible) {
|
||||
if (!Complain) {
|
||||
RefRelationship >= Ref_Compatible_With_Added_Qualification) {
|
||||
if (ICS) {
|
||||
ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||
ICS->Standard.First = ICK_Identity;
|
||||
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
|
||||
ICS->Standard.Third = ICK_Identity;
|
||||
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
|
||||
ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
|
||||
ICS->ReferenceBinding = true;
|
||||
ICS->DirectBinding = false;
|
||||
} else {
|
||||
// FIXME: Binding to a subobject of the rvalue is going to require
|
||||
// more AST annotation than this.
|
||||
ImpCastExprToType(Init, T1);
|
||||
@ -853,7 +898,7 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
// we would be reference-compatible or reference-compatible with
|
||||
// added qualification. But that wasn't the case, so the reference
|
||||
// initialization fails.
|
||||
if (Complain)
|
||||
if (!ICS)
|
||||
Diag(Init->getSourceRange().getBegin(),
|
||||
diag::err_reference_init_drops_quals,
|
||||
T1.getAsString(),
|
||||
@ -863,9 +908,21 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
|
||||
}
|
||||
|
||||
// Actually try to convert the initializer to T1.
|
||||
if (Complain)
|
||||
if (ICS) {
|
||||
/// C++ [over.ics.ref]p2:
|
||||
///
|
||||
/// When a parameter of reference type is not bound directly to
|
||||
/// an argument expression, the conversion sequence is the one
|
||||
/// required to convert the argument expression to the
|
||||
/// underlying type of the reference according to
|
||||
/// 13.3.3.1. Conceptually, this conversion sequence corresponds
|
||||
/// to copy-initializing a temporary of the underlying type with
|
||||
/// the argument expression. Any difference in top-level
|
||||
/// cv-qualification is subsumed by the initialization itself
|
||||
/// and does not constitute a conversion.
|
||||
*ICS = TryImplicitConversion(Init, T1);
|
||||
return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
|
||||
} else {
|
||||
return PerformImplicitConversion(Init, T1);
|
||||
else
|
||||
return (TryImplicitConversion(Init, T1).ConversionKind
|
||||
== ImplicitConversionSequence::BadConversion);
|
||||
}
|
||||
}
|
||||
|
@ -1123,7 +1123,7 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
||||
Fn->getSourceRange());
|
||||
|
||||
// We know the result type of the call, set it.
|
||||
TheCall->setType(FuncT->getResultType());
|
||||
TheCall->setType(FuncT->getResultType().getNonReferenceType());
|
||||
|
||||
if (const FunctionTypeProto *Proto = dyn_cast<FunctionTypeProto>(FuncT)) {
|
||||
// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
|
||||
|
@ -39,6 +39,7 @@ GetConversionCategory(ImplicitConversionKind Kind) {
|
||||
ICC_Conversion,
|
||||
ICC_Conversion,
|
||||
ICC_Conversion,
|
||||
ICC_Conversion,
|
||||
ICC_Conversion
|
||||
};
|
||||
return Category[(int)Kind];
|
||||
@ -61,6 +62,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
|
||||
ICR_Conversion,
|
||||
ICR_Conversion,
|
||||
ICR_Conversion,
|
||||
ICR_Conversion,
|
||||
ICR_Conversion
|
||||
};
|
||||
return Rank[(int)Kind];
|
||||
@ -82,7 +84,8 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
|
||||
"Floating-integral conversion",
|
||||
"Pointer conversion",
|
||||
"Pointer-to-member conversion",
|
||||
"Boolean conversion"
|
||||
"Boolean conversion",
|
||||
"Derived-to-base conversion"
|
||||
};
|
||||
return Name[Kind];
|
||||
}
|
||||
@ -1066,10 +1069,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType) {
|
||||
return ICS;
|
||||
} else if (ToType->isReferenceType()) {
|
||||
ImplicitConversionSequence ICS;
|
||||
if (CheckReferenceInit(From, ToType, /*Complain=*/false))
|
||||
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
|
||||
else
|
||||
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||
CheckReferenceInit(From, ToType, &ICS);
|
||||
return ICS;
|
||||
} else {
|
||||
return TryImplicitConversion(From, ToType);
|
||||
|
@ -38,6 +38,7 @@ namespace clang {
|
||||
ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10)
|
||||
ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11)
|
||||
ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
|
||||
ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics][)
|
||||
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
|
||||
};
|
||||
|
||||
@ -91,9 +92,9 @@ namespace clang {
|
||||
/// Third - The third conversion can be a qualification conversion.
|
||||
ImplicitConversionKind Third : 8;
|
||||
|
||||
/// Deprecated - Whether this is a deprecated conversion, such as
|
||||
/// converting a string literal to a pointer to non-const
|
||||
/// character data (C++ 4.2p2).
|
||||
/// Deprecated - Whether this the deprecated conversion of a
|
||||
/// string literal to a pointer to non-const character data
|
||||
/// (C++ 4.2p2).
|
||||
bool Deprecated : 1;
|
||||
|
||||
/// FromType - The type that this conversion is converting
|
||||
@ -154,7 +155,17 @@ namespace clang {
|
||||
};
|
||||
|
||||
/// ConversionKind - The kind of implicit conversion sequence.
|
||||
Kind ConversionKind;
|
||||
/// As usual, we use "unsigned" here because VC++ makes enum bitfields
|
||||
/// signed.
|
||||
unsigned ConversionKind : 2;
|
||||
|
||||
/// ReferenceBinding - True when this is a reference binding
|
||||
/// (C++ [over.ics.ref]).
|
||||
bool ReferenceBinding : 1;
|
||||
|
||||
/// DirectBinding - True when this is a reference binding that is a
|
||||
/// direct binding (C++ [dcl.init.ref]).
|
||||
bool DirectBinding : 1;
|
||||
|
||||
union {
|
||||
/// When ConversionKind == StandardConversion, provides the
|
||||
|
@ -225,3 +225,31 @@ void intref_test() {
|
||||
float* ir1 = intref(5);
|
||||
float* ir2 = intref(5.5);
|
||||
}
|
||||
|
||||
// Test reference binding vs. standard conversions.
|
||||
int& bind_vs_conv(const double&);
|
||||
float& bind_vs_conv(int);
|
||||
|
||||
void bind_vs_conv_test()
|
||||
{
|
||||
int& i1 = bind_vs_conv(1.0f);
|
||||
float& f1 = bind_vs_conv((short)1);
|
||||
}
|
||||
|
||||
// Test that cv-qualifiers get subsumed in the reference binding.
|
||||
struct X { };
|
||||
struct Y { };
|
||||
struct Z : X, Y { };
|
||||
|
||||
int& cvqual_subsume(X&); // expected-note{{candidate function}}
|
||||
float& cvqual_subsume(const Y&); // expected-note{{candidate function}}
|
||||
|
||||
int& cvqual_subsume2(const X&);
|
||||
float& cvqual_subsume2(const volatile Y&);
|
||||
|
||||
Z get_Z();
|
||||
|
||||
void cvqual_subsume_test(Z z) {
|
||||
cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous; candidates are:}}
|
||||
int& x = cvqual_subsume2(get_Z()); // okay: only binds to the first one
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user