[cfe-commits] r58357 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overload-call.cpp
Douglas Gregor
doug.gregor at gmail.com
Tue Oct 28 19:00:59 PDT 2008
Author: dgregor
Date: Tue Oct 28 21:00:59 2008
New Revision: 58357
URL: http://llvm.org/viewvc/llvm-project?rev=58357&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaOverload.h
cfe/trunk/test/SemaCXX/overload-call.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58357&r1=58356&r2=58357&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Oct 28 21:00:59 2008
@@ -1139,10 +1139,11 @@
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);
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58357&r1=58356&r2=58357&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Oct 28 21:00:59 2008
@@ -688,7 +688,8 @@
/// 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 @@
// 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 @@
/// 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 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
}
// 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);
+ }
}
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=58357&r1=58356&r2=58357&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 28 21:00:59 2008
@@ -1123,7 +1123,7 @@
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
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=58357&r1=58356&r2=58357&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 28 21:00:59 2008
@@ -39,6 +39,7 @@
ICC_Conversion,
ICC_Conversion,
ICC_Conversion,
+ ICC_Conversion,
ICC_Conversion
};
return Category[(int)Kind];
@@ -61,6 +62,7 @@
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
+ ICR_Conversion,
ICR_Conversion
};
return Rank[(int)Kind];
@@ -82,7 +84,8 @@
"Floating-integral conversion",
"Pointer conversion",
"Pointer-to-member conversion",
- "Boolean conversion"
+ "Boolean conversion",
+ "Derived-to-base conversion"
};
return Name[Kind];
}
@@ -1066,10 +1069,7 @@
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);
Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=58357&r1=58356&r2=58357&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Tue Oct 28 21:00:59 2008
@@ -38,6 +38,7 @@
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 @@
/// 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 @@
};
/// 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
Modified: cfe/trunk/test/SemaCXX/overload-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=58357&r1=58356&r2=58357&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Tue Oct 28 21:00:59 2008
@@ -225,3 +225,31 @@
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
+}
More information about the cfe-commits
mailing list