diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-10-29 02:00:59 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-10-29 02:00:59 +0000 |
commit | 786ab2119f288bd00e0c6583ecf46e90ecfa6a5c (patch) | |
tree | 10ce91f7f6fa40021f3c8fe665b97b8e22c01abb | |
parent | cfa9d8e9a086287d11326b59e61a3200cbbf812a (diff) | |
download | bcm5719-llvm-786ab2119f288bd00e0c6583ecf46e90ecfa6a5c.tar.gz bcm5719-llvm-786ab2119f288bd00e0c6583ecf46e90ecfa6a5c.zip |
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
-rw-r--r-- | clang/lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 117 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.h | 19 | ||||
-rw-r--r-- | clang/test/SemaCXX/overload-call.cpp | 28 |
6 files changed, 139 insertions, 42 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 87d7cd139f1..1cff55ea243 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7e35ff4df3a..ef9ed9ba13d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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); + } } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 831765376b6..b23db487677 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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 diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 8e765485b11..551f61a56e8 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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); diff --git a/clang/lib/Sema/SemaOverload.h b/clang/lib/Sema/SemaOverload.h index 27190f6e996..558718c0d94 100644 --- a/clang/lib/Sema/SemaOverload.h +++ b/clang/lib/Sema/SemaOverload.h @@ -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 diff --git a/clang/test/SemaCXX/overload-call.cpp b/clang/test/SemaCXX/overload-call.cpp index 663474d3282..81e437a72f7 100644 --- a/clang/test/SemaCXX/overload-call.cpp +++ b/clang/test/SemaCXX/overload-call.cpp @@ -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 +} |