From: Douglas Gregor Date: Mon, 10 Nov 2008 16:14:15 +0000 (+0000) Subject: Allow user-defined conversions during reference binding X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cb9b977d5989efc1e5bc7684091912ca2915aacb;p=clang Allow user-defined conversions during reference binding git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58988 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index dd00998d41..3495880d22 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1591,9 +1591,69 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, // 92) (this conversion is selected by enumerating the // 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. Also remember C++ [over.ics.ref]p1, second part. + if (!SuppressUserConversions && T2->isRecordType()) { + // FIXME: Look for conversions in base classes! + CXXRecordDecl *T2RecordDecl + = dyn_cast(T2->getAsRecordType()->getDecl()); + + OverloadCandidateSet CandidateSet; + OverloadedFunctionDecl *Conversions + = T2RecordDecl->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func + = Conversions->function_begin(); + Func != Conversions->function_end(); ++Func) { + CXXConversionDecl *Conv = cast(*Func); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion. + // FIXME: This will change when we support rvalue references. + if (Conv->getConversionType()->isReferenceType()) + AddConversionCandidate(Conv, Init, DeclType, CandidateSet); + } + + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // This is a direct binding. + BindsDirectly = true; + + if (ICS) { + // C++ [over.ics.ref]p1: + // + // [...] If the parameter binds directly to the result of + // applying a conversion function to the argument + // expression, the implicit conversion sequence is a + // user-defined conversion sequence (13.3.3.1.2), with the + // second standard conversion sequence either an identity + // conversion or, if the conversion function returns an + // entity of a type that is a derived class of the parameter + // type, a derived-to-base Conversion. + ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS->UserDefined.Before = Best->Conversions[0].Standard; + ICS->UserDefined.After = Best->FinalConversion; + ICS->UserDefined.ConversionFunction = Best->Function; + assert(ICS->UserDefined.After.ReferenceBinding && + ICS->UserDefined.After.DirectBinding && + "Expected a direct reference binding!"); + 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); + } + break; + case OR_Ambiguous: + assert(false && "Ambiguous reference binding conversions not implemented."); + return true; + + case OR_No_Viable_Function: + // There was no suitable conversion; continue with other checks. + break; + } + } + if (BindsDirectly) { // C++ [dcl.init.ref]p4: // [...] In all cases where the reference-related or diff --git a/test/SemaCXX/user-defined-conversions.cpp b/test/SemaCXX/user-defined-conversions.cpp index b85593318d..8292c7a009 100644 --- a/test/SemaCXX/user-defined-conversions.cpp +++ b/test/SemaCXX/user-defined-conversions.cpp @@ -19,4 +19,19 @@ void g(int); void g_test(Y y) { g(y); + short s; + s = y; +} + +struct A { }; +struct B : A { }; + +struct C { + operator B&(); +}; + +// Test reference binding via an lvalue conversion function. +void h(volatile A&); +void h_test(C c) { + h(c); }