From: John McCall Date: Tue, 12 Jan 2010 00:44:57 +0000 (+0000) Subject: Introduce a specific representation for the ambiguous implicit conversion X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1d31833450e6d2947a33cb0840d87661d92eec07;p=clang Introduce a specific representation for the ambiguous implicit conversion sequence. Lots of small relevant changes. Fixes some serious problems with ambiguous conversions; also possibly improves associated diagnostics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93214 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f463cbb7c8..00f6b2cd63 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1044,6 +1044,9 @@ public: SourceLocation Loc = SourceLocation()); void NoteOverloadCandidate(FunctionDecl *Fn); + void DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag); FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 800c544d33..f924bd3bb1 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -893,7 +893,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /*InOverloadResolution=*/false, /*one of user provided casts*/true); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + if (ICS.isBad()) return TC_NotApplicable; // The conversion is possible, so commit to it. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e10013e3a5..93a873afc5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4389,8 +4389,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); // Most paths end in a failed conversion. - if (ICS) - ICS->ConversionKind = ImplicitConversionSequence::BadConversion; + if (ICS) ICS->setBad(); // C++ [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression @@ -4428,7 +4427,7 @@ Sema::CheckReferenceInit(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->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->setStandard(); ICS->Standard.First = ICK_Identity; ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; @@ -4513,7 +4512,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // 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->setUserDefined(); ICS->UserDefined.Before = Best->Conversions[0].Standard; ICS->UserDefined.After = Best->FinalConversion; ICS->UserDefined.ConversionFunction = Best->Function; @@ -4539,10 +4538,11 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, case OR_Ambiguous: if (ICS) { + ICS->setAmbiguous(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) if (Cand->Viable) - ICS->ConversionFunctionSet.push_back(Cand->Function); + ICS->Ambiguous.addConversion(Cand->Function); break; } Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() @@ -4616,7 +4616,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && RefRelationship >= Ref_Compatible_With_Added_Qualification) { if (ICS) { - ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->setStandard(); ICS->Standard.First = ICK_Identity; ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; @@ -4688,29 +4688,26 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, /*InOverloadResolution=*/false); // Of course, that's still a reference binding. - if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) { + if (ICS->isStandard()) { ICS->Standard.ReferenceBinding = true; ICS->Standard.RRefBinding = isRValRef; - } else if (ICS->ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) { + } else if (ICS->isUserDefined()) { ICS->UserDefined.After.ReferenceBinding = true; ICS->UserDefined.After.RRefBinding = isRValRef; } - return ICS->ConversionKind == ImplicitConversionSequence::BadConversion; + return ICS->isBad(); } else { ImplicitConversionSequence Conversions; bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, false, false, Conversions); if (badConversion) { - if ((Conversions.ConversionKind == - ImplicitConversionSequence::BadConversion) - && !Conversions.ConversionFunctionSet.empty()) { + if (Conversions.isAmbiguous()) { Diag(DeclLoc, diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); - for (int j = Conversions.ConversionFunctionSet.size()-1; + for (int j = Conversions.Ambiguous.conversions().size()-1; j >= 0; j--) { - FunctionDecl *Func = Conversions.ConversionFunctionSet[j]; + FunctionDecl *Func = Conversions.Ambiguous.conversions()[j]; NoteOverloadCandidate(Func); } } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 6407441aa1..e655184dbf 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1075,7 +1075,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS) { - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); if (Elidable && getLangOptions().CPlusPlus0x) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, @@ -1083,7 +1083,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /*ForceRValue=*/true, /*InOverloadResolution=*/false); } - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, AllowExplicit, @@ -1103,7 +1103,7 @@ bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, bool IgnoreBaseAccess) { - switch (ICS.ConversionKind) { + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, IgnoreBaseAccess)) @@ -1157,6 +1157,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, IgnoreBaseAccess); } + + case ImplicitConversionSequence::AmbiguousConversion: + DiagnoseAmbiguousConversion(ICS, From->getExprLoc(), + PDiag(diag::err_typecheck_ambiguous_condition) + << From->getSourceRange()); + return true; case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); @@ -1474,14 +1480,18 @@ QualType Sema::CheckPointerToMemberOperands( /// \brief Get the target type of a standard or user-defined conversion. static QualType TargetType(const ImplicitConversionSequence &ICS) { - assert((ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion || - ICS.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) && - "function only valid for standard or user-defined conversions"); - if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion) - return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr); - return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); + switch (ICS.getKind()) { + case ImplicitConversionSequence::StandardConversion: + return ICS.Standard.getToType(); + case ImplicitConversionSequence::UserDefinedConversion: + return ICS.UserDefined.After.getToType(); + case ImplicitConversionSequence::AmbiguousConversion: + return ICS.Ambiguous.getToType(); + case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::BadConversion: + llvm_unreachable("function not valid for ellipsis or bad conversions"); + } + return QualType(); // silence warnings } /// \brief Try to convert a type to another according to C++0x 5.16p3. @@ -1511,19 +1521,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, /*ForceRValue=*/false, &ICS)) { - assert((ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion || - ICS.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) && + assert((ICS.isStandard() || ICS.isUserDefined()) && "expected a definite conversion"); bool DirectBinding = - ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ? - ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding; + ICS.isStandard() ? ICS.Standard.DirectBinding + : ICS.UserDefined.After.DirectBinding; if (DirectBinding) return false; } } - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: @@ -1619,8 +1626,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// handles the reference binding specially. static bool ConvertForConditional(Sema &Self, Expr *&E, const ImplicitConversionSequence &ICS) { - if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion && - ICS.Standard.ReferenceBinding) { + if (ICS.isStandard() && ICS.Standard.ReferenceBinding) { assert(ICS.Standard.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); // FIXME: CheckReferenceInit should be able to reuse the ICS instead of @@ -1632,8 +1638,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, /*AllowExplicit=*/false, /*ForceRValue=*/false); } - if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion && - ICS.UserDefined.After.ReferenceBinding) { + if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) { assert(ICS.UserDefined.After.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( @@ -1721,10 +1726,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft)) return QualType(); - bool HaveL2R = ICSLeftToRight.ConversionKind != - ImplicitConversionSequence::BadConversion; - bool HaveR2L = ICSRightToLeft.ConversionKind != - ImplicitConversionSequence::BadConversion; + bool HaveL2R = !ICSLeftToRight.isBad(); + bool HaveR2L = !ICSRightToLeft.isBad(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -1938,8 +1941,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*InOverloadResolution=*/false); ImplicitConversionSequence E1ToC2, E2ToC2; - E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; - E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; + E1ToC2.setBad(); + E2ToC2.setBad(); if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { E1ToC2 = TryImplicitConversion(E1, Composite2, @@ -1954,14 +1957,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*InOverloadResolution=*/false); } - bool ToC1Viable = E1ToC1.ConversionKind != - ImplicitConversionSequence::BadConversion - && E2ToC1.ConversionKind != - ImplicitConversionSequence::BadConversion; - bool ToC2Viable = E1ToC2.ConversionKind != - ImplicitConversionSequence::BadConversion - && E2ToC2.ConversionKind != - ImplicitConversionSequence::BadConversion; + bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); + bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); if (ToC1Viable && !ToC2Viable) { if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 8c45edb21f..8701f41de4 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -670,7 +670,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) { + if (!ICS.isBad()) { if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, Sema::AA_Initializing)) hadError = true; @@ -2300,6 +2300,11 @@ static void TryReferenceInitialization(Sema &S, Sequence); if (ConvOvlResult == OR_Success) return; + if (ConvOvlResult != OR_No_Viable_Function) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + } } } @@ -2384,7 +2389,7 @@ static void TryReferenceInitialization(Sema &S, /*FIXME:InOverloadResolution=*/false, /*UserCast=*/Kind.isExplicitCast()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { // FIXME: Use the conversion function set stored in ICS to turn // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some @@ -2685,14 +2690,14 @@ static void TryUserDefinedConversion(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result + if (OverloadingResult Result = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_UserConversionOverloadFailed, Result); return; } - + FunctionDecl *Function = Best->Function; if (isa(Function)) { @@ -2711,7 +2716,7 @@ static void TryUserDefinedConversion(Sema &S, if (Best->FinalConversion.First || Best->FinalConversion.Second || Best->FinalConversion.Third) { ImplicitConversionSequence ICS; - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); ICS.Standard = Best->FinalConversion; Sequence.AddConversionSequenceStep(ICS, DestType); } @@ -2732,7 +2737,7 @@ static void TryImplicitConversion(Sema &S, /*FIXME:InOverloadResolution=*/false, /*UserCast=*/Kind.isExplicitCast()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); return; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 05e06a33ef..74b548cb96 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -145,15 +145,12 @@ ImplicitConversionRank StandardConversionSequence::getRank() const { /// used as part of the ranking of standard conversion sequences /// (C++ 13.3.3.2p4). bool StandardConversionSequence::isPointerConversionToBool() const { - QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); - QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); - // Note that FromType has not necessarily been transformed by the // array-to-pointer or function-to-pointer implicit conversions, so // check for their presence as well as checking whether FromType is // a pointer. - if (ToType->isBooleanType() && - (FromType->isPointerType() || FromType->isBlockPointerType() || + if (getToType()->isBooleanType() && + (getFromType()->isPointerType() || getFromType()->isBlockPointerType() || First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) return true; @@ -167,8 +164,8 @@ bool StandardConversionSequence::isPointerConversionToBool() const { bool StandardConversionSequence:: isPointerConversionToVoidPointer(ASTContext& Context) const { - QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); - QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); + QualType FromType = getFromType(); + QualType ToType = getToType(); // Note that FromType has not necessarily been transformed by the // array-to-pointer implicit conversion, so check for its presence @@ -250,6 +247,9 @@ void ImplicitConversionSequence::DebugPrint() const { case EllipsisConversion: fprintf(stderr, "Ellipsis conversion"); break; + case AmbiguousConversion: + fprintf(stderr, "Ambiguous conversion"); + break; case BadConversion: fprintf(stderr, "Bad conversion"); break; @@ -258,6 +258,22 @@ void ImplicitConversionSequence::DebugPrint() const { fprintf(stderr, "\n"); } +void AmbiguousConversionSequence::construct() { + new (&conversions()) ConversionSet(); +} + +void AmbiguousConversionSequence::destruct() { + conversions().~ConversionSet(); +} + +void +AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) { + FromTypePtr = O.FromTypePtr; + ToTypePtr = O.ToTypePtr; + new (&conversions()) ConversionSet(O.conversions()); +} + + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -432,14 +448,14 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, OverloadCandidateSet Conversions; OverloadingResult UserDefResult = OR_Success; if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); else if (getLangOptions().CPlusPlus && (UserDefResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, !SuppressUserConversions, AllowExplicit, ForceRValue, UserCast)) == OR_Success) { - ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS.setUserDefined(); // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class // type is given Exact Match rank, and a conversion of an @@ -456,10 +472,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) { // Turn this into a "standard" conversion sequence, so that it // gets ranked with standard conversion sequences. - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); - ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr(); - ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr(); + ICS.Standard.setFromType(From->getType()); + ICS.Standard.setToType(ToType); ICS.Standard.CopyConstructor = Constructor; if (ToCanon != FromCanon) ICS.Standard.Second = ICK_Derived_To_Base; @@ -473,17 +489,18 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or // 13.3.1.6 in all cases, only standard conversion sequences and // ellipsis conversion sequences are allowed. - if (SuppressUserConversions && - ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + if (SuppressUserConversions && ICS.isUserDefined()) + ICS.setBad(); + } else if (UserDefResult == OR_Ambiguous) { + ICS.setAmbiguous(); + ICS.Ambiguous.setFromType(From->getType()); + ICS.Ambiguous.setToType(ToType); + for (OverloadCandidateSet::iterator Cand = Conversions.begin(); + Cand != Conversions.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); } else { - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - if (UserDefResult == OR_Ambiguous) { - for (OverloadCandidateSet::iterator Cand = Conversions.begin(); - Cand != Conversions.end(); ++Cand) - if (Cand->Viable) - ICS.ConversionFunctionSet.push_back(Cand->Function); - } + ICS.setBad(); } return ICS; @@ -524,7 +541,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.setAsIdentityConversion(); SCS.Deprecated = false; SCS.IncompatibleObjC = false; - SCS.FromTypePtr = FromType.getAsOpaquePtr(); + SCS.setFromType(FromType); SCS.CopyConstructor = 0; // There are no standard conversions for class types in C++, so @@ -573,7 +590,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // conversion (4.4). (C++ 4.2p2) SCS.Second = ICK_Identity; SCS.Third = ICK_Qualification; - SCS.ToTypePtr = ToType.getAsOpaquePtr(); + SCS.setToType(ToType); return true; } } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { @@ -724,7 +741,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, if (CanonFrom != CanonTo) return false; - SCS.ToTypePtr = FromType.getAsOpaquePtr(); + SCS.setToType(FromType); return true; } @@ -1544,8 +1561,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // the argument of the constructor. // QualType ThisType = Constructor->getThisType(Context); - if (Best->Conversions[0].ConversionKind == - ImplicitConversionSequence::EllipsisConversion) + if (Best->Conversions[0].isEllipsis()) User.EllipsisConversion = true; else { User.Before = Best->Conversions[0].Standard; @@ -1553,9 +1569,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, } User.ConversionFunction = Constructor; User.After.setAsIdentityConversion(); - User.After.FromTypePtr - = ThisType->getAs()->getPointeeType().getAsOpaquePtr(); - User.After.ToTypePtr = ToType.getAsOpaquePtr(); + User.After.setFromType( + ThisType->getAs()->getPointeeType()); + User.After.setToType(ToType); return OR_Success; } else if (CXXConversionDecl *Conversion = dyn_cast(Best->Function)) { @@ -1635,18 +1651,28 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // conversion sequence than an ellipsis conversion sequence // (13.3.3.1.3). // - if (ICS1.ConversionKind < ICS2.ConversionKind) - return ImplicitConversionSequence::Better; - else if (ICS2.ConversionKind < ICS1.ConversionKind) - return ImplicitConversionSequence::Worse; + // C++0x [over.best.ics]p10: + // For the purpose of ranking implicit conversion sequences as + // described in 13.3.3.2, the ambiguous conversion sequence is + // treated as a user-defined sequence that is indistinguishable + // from any other user-defined conversion sequence. + if (ICS1.getKind() < ICS2.getKind()) { + if (!(ICS1.isUserDefined() && ICS2.isAmbiguous())) + return ImplicitConversionSequence::Better; + } else if (ICS2.getKind() < ICS1.getKind()) { + if (!(ICS2.isUserDefined() && ICS1.isAmbiguous())) + return ImplicitConversionSequence::Worse; + } + + if (ICS1.isAmbiguous() || ICS2.isAmbiguous()) + return ImplicitConversionSequence::Indistinguishable; // Two implicit conversion sequences of the same form are // indistinguishable conversion sequences unless one of the // following rules apply: (C++ 13.3.3.2p3): - if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion) + if (ICS1.isStandard()) return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard); - else if (ICS1.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) { + else if (ICS1.isUserDefined()) { // User-defined conversion sequence U1 is a better conversion // sequence than another user-defined conversion sequence U2 if // they contain the same user-defined conversion function or @@ -1739,8 +1765,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Both conversion sequences are conversions to void // pointers. Compare the source types to determine if there's an // inheritance relationship in their sources. - QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); - QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); + QualType FromType1 = SCS1.getFromType(); + QualType FromType2 = SCS2.getFromType(); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -1796,8 +1822,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // top-level cv-qualifiers, and the type to which the reference // initialized by S2 refers is more cv-qualified than the type // to which the reference initialized by S1 refers. - QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType T1 = SCS1.getToType(); + QualType T2 = SCS2.getToType(); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; @@ -1927,10 +1953,10 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, ImplicitConversionSequence::CompareKind Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { - QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); - QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); - QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType FromType1 = SCS1.getFromType(); + QualType ToType1 = SCS1.getToType(); + QualType FromType2 = SCS2.getFromType(); + QualType ToType2 = SCS2.getToType(); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -2175,7 +2201,7 @@ Sema::TryObjectArgumentInitialization(QualType FromType, // to exit early. ImplicitConversionSequence ICS; ICS.Standard.setAsIdentityConversion(); - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); // We need to have an object of class type. if (const PointerType *PT = FromType->getAs()) @@ -2211,9 +2237,9 @@ Sema::TryObjectArgumentInitialization(QualType FromType, return ICS; // Success. Mark this as a reference binding. - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; - ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr(); - ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr(); + ICS.setStandard(); + ICS.Standard.setFromType(FromType); + ICS.Standard.setToType(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; ICS.Standard.RRefBinding = false; @@ -2242,7 +2268,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { ImplicitConversionSequence ICS = TryObjectArgumentInitialization(From->getType(), Method, Method->getParent()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + if (ICS.isBad()) return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); @@ -2274,8 +2300,8 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { /// of the expression From to bool (C++0x [conv]p3). bool Sema::PerformContextuallyConvertToBool(Expr *&From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); - if (!PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting)) - return false; + if (!ICS.isBad()) + return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getSourceRange().getBegin(), @@ -2388,35 +2414,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, = TryCopyInitialization(Args[ArgIdx], ParamType, SuppressUserConversions, ForceRValue, /*InOverloadResolution=*/true); - if (Candidate.Conversions[ArgIdx].ConversionKind - == ImplicitConversionSequence::BadConversion) { - // 13.3.3.1-p10 If several different sequences of conversions exist that - // each convert the argument to the parameter type, the implicit conversion - // sequence associated with the parameter is defined to be the unique conversion - // sequence designated the ambiguous conversion sequence. For the purpose of - // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous - // conversion sequence is treated as a user-defined sequence that is - // indistinguishable from any other user-defined conversion sequence - if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) { - Candidate.Conversions[ArgIdx].ConversionKind = - ImplicitConversionSequence::UserDefinedConversion; - // Set the conversion function to one of them. As due to ambiguity, - // they carry the same weight and is needed for overload resolution - // later. - Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction = - Candidate.Conversions[ArgIdx].ConversionFunctionSet[0]; - } - else { - Candidate.Viable = false; - break; - } + if (Candidate.Conversions[ArgIdx].isBad()) { + Candidate.Viable = false; + break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx].setEllipsis(); } } } @@ -2552,8 +2558,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // parameter. Candidate.Conversions[0] = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); - if (Candidate.Conversions[0].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; return; } @@ -2572,8 +2577,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, = TryCopyInitialization(Args[ArgIdx], ParamType, SuppressUserConversions, ForceRValue, /*InOverloadResolution=*/true); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; break; } @@ -2581,8 +2585,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx + 1].setEllipsis(); } } } @@ -2706,9 +2709,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); - Candidate.FinalConversion.FromTypePtr - = Conversion->getConversionType().getAsOpaquePtr(); - Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr(); + Candidate.FinalConversion.setFromType(Conversion->getConversionType()); + Candidate.FinalConversion.setToType(ToType); // Determine the implicit conversion sequence for the implicit // object parameter. @@ -2722,8 +2724,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // in overload resolution. if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base) Candidate.Conversions[0].Standard.Second = ICK_Identity; - if (Candidate.Conversions[0].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; return; } @@ -2766,7 +2767,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - switch (ICS.ConversionKind) { + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; break; @@ -2844,7 +2845,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // object parameter. ImplicitConversionSequence ObjectInit = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); - if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ObjectInit.isBad()) { Candidate.Viable = false; return; } @@ -2852,8 +2853,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // The first conversion is actually a user-defined conversion whose // first conversion is ObjectInit's standard conversion (which is // effectively a reference binding). Record it as such. - Candidate.Conversions[0].ConversionKind - = ImplicitConversionSequence::UserDefinedConversion; + Candidate.Conversions[0].setUserDefined(); Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; @@ -2894,8 +2894,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, /*SuppressUserConversions=*/false, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; break; } @@ -2903,8 +2902,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx + 1].setEllipsis(); } } } @@ -3038,8 +3036,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, /*ForceRValue=*/false, /*InOverloadResolution=*/false); } - if (Candidate.Conversions[ArgIdx].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; break; } @@ -4304,11 +4301,22 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { Diag(Fn->getLocation(), diag::note_ovl_candidate); } -namespace { - -void NoteDeletedCandidate(Sema &S, OverloadCandidate *Cand) { +/// Diagnoses an ambiguous conversion. The partial diagnostic is the +/// "lead" diagnostic; it will be given two arguments, the source and +/// target types of the conversion. +void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) { + Diag(CaretLoc, PDiag) + << ICS.Ambiguous.getFromType() << ICS.Ambiguous.getToType(); + for (AmbiguousConversionSequence::const_iterator + I = ICS.Ambiguous.begin(), E = ICS.Ambiguous.end(); I != E; ++I) { + NoteOverloadCandidate(*I); + } } +namespace { + void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand) { // Note deleted candidates, but only if they're viable. if (Cand->Viable && @@ -4335,18 +4343,13 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand) { for (int i = Cand->Conversions.size()-1; i >= 0; i--) { const ImplicitConversionSequence &Conversion = Cand->Conversions[i]; - if ((Conversion.ConversionKind != - ImplicitConversionSequence::BadConversion) || - Conversion.ConversionFunctionSet.size() == 0) + + if (!Conversion.isAmbiguous()) continue; - S.Diag(Cand->Function->getLocation(), - diag::note_ovl_candidate_not_viable) << (i+1); + + S.DiagnoseAmbiguousConversion(Conversion, Cand->Function->getLocation(), + PDiag(diag::note_ovl_candidate_not_viable) << (i+1)); errReported = true; - for (int j = Conversion.ConversionFunctionSet.size()-1; - j >= 0; j--) { - FunctionDecl *Func = Conversion.ConversionFunctionSet[j]; - S.NoteOverloadCandidate(Func); - } } } @@ -4411,21 +4414,11 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, unsigned NoOperands = Cand->Conversions.size(); for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; - if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion || - ICS.ConversionFunctionSet.empty()) - continue; - if (CXXConversionDecl *Func = dyn_cast( - Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) { - QualType FromTy = - QualType(static_cast(ICS.UserDefined.Before.FromTypePtr),0); - S.Diag(OpLoc, diag::note_ambiguous_type_conversion) - << FromTy << Func->getConversionType(); - } - for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) { - FunctionDecl *Func = - Cand->Conversions[ArgIdx].ConversionFunctionSet[j]; - S.NoteOverloadCandidate(Func); - } + if (ICS.isBad()) break; // all meaningless after first invalid + if (!ICS.isAmbiguous()) continue; + + S.DiagnoseAmbiguousConversion(ICS, OpLoc, + PDiag(diag::note_ambiguous_type_conversion)); } } @@ -4479,7 +4472,7 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, Cands.push_back(Cand); std::sort(Cands.begin(), Cands.end(), CompareOverloadCandidates(SourceMgr)); - bool ReportedNonViableOperator = false; + bool ReportedAmbiguousConversions = false; llvm::SmallVectorImpl::iterator I, E; for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { @@ -4492,16 +4485,20 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, // This a builtin candidate. We do not, in general, want to list // every possible builtin candidate. + else if (Cand->Viable) { + // Generally we only see ambiguities including viable builtin + // operators if overload resolution got screwed up by an + // ambiguous user-defined conversion. + // + // FIXME: It's quite possible for different conversions to see + // different ambiguities, though. + if (!ReportedAmbiguousConversions) { + NoteAmbiguousUserConversions(*this, OpLoc, Cand); + ReportedAmbiguousConversions = true; + } - // If this is a viable builtin, print it. - else if (Cand->Viable) + // If this is a viable builtin, print it. NoteBuiltinOperatorCandidate(*this, Opc, OpLoc, Cand); - - // Otherwise, non-viability might be due to ambiguous user-defined - // conversions. Report them exactly once. - else if (!ReportedNonViableOperator) { - NoteAmbiguousUserConversions(*this, OpLoc, Cand); - ReportedNonViableOperator = true; } } } @@ -5414,7 +5411,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << Args[0]->getSourceRange() << Args[1]->getSourceRange(); PrintOverloadCandidates(CandidateSet, OCD_AllCandidates); return ExprError(); - } + } // We matched a built-in operator; build it. return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 3613d60883..78fa05b24c 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -149,6 +149,15 @@ namespace clang { /// conversions. CXXConstructorDecl *CopyConstructor; + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setAsIdentityConversion(); ImplicitConversionRank getRank() const; bool isPointerConversionToBool() const; @@ -190,6 +199,48 @@ namespace clang { void DebugPrint() const; }; + /// Represents an ambiguous user-defined conversion sequence. + struct AmbiguousConversionSequence { + typedef llvm::SmallVector ConversionSet; + + void *FromTypePtr; + void *ToTypePtr; + char Buffer[sizeof(ConversionSet)]; + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + + ConversionSet &conversions() { + return *reinterpret_cast(Buffer); + } + + const ConversionSet &conversions() const { + return *reinterpret_cast(Buffer); + } + + void addConversion(FunctionDecl *D) { + conversions().push_back(D); + } + + typedef ConversionSet::iterator iterator; + iterator begin() { return conversions().begin(); } + iterator end() { return conversions().end(); } + + typedef ConversionSet::const_iterator const_iterator; + const_iterator begin() const { return conversions().begin(); } + const_iterator end() const { return conversions().end(); } + + void construct(); + void destruct(); + void copyFrom(const AmbiguousConversionSequence &); + }; + /// ImplicitConversionSequence - Represents an implicit conversion /// sequence, which may be a standard conversion sequence /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), @@ -197,18 +248,26 @@ namespace clang { struct ImplicitConversionSequence { /// Kind - The kind of implicit conversion sequence. BadConversion /// specifies that there is no conversion from the source type to - /// the target type. The enumerator values are ordered such that - /// better implicit conversions have smaller values. + /// the target type. AmbiguousConversion represents the unique + /// ambiguous conversion (C++0x [over.best.ics]p10). enum Kind { StandardConversion = 0, UserDefinedConversion, + AmbiguousConversion, EllipsisConversion, BadConversion }; + private: /// ConversionKind - The kind of implicit conversion sequence. Kind ConversionKind; + void setKind(Kind K) { + if (isAmbiguous()) Ambiguous.destruct(); + ConversionKind = K; + } + + public: union { /// When ConversionKind == StandardConversion, provides the /// details of the standard conversion sequence. @@ -217,12 +276,54 @@ namespace clang { /// When ConversionKind == UserDefinedConversion, provides the /// details of the user-defined conversion sequence. UserDefinedConversionSequence UserDefined; + + /// When ConversionKind == AmbiguousConversion, provides the + /// details of the ambiguous conversion. + AmbiguousConversionSequence Ambiguous; }; + + ImplicitConversionSequence() : ConversionKind(BadConversion) {} + ~ImplicitConversionSequence() { + if (isAmbiguous()) Ambiguous.destruct(); + } + ImplicitConversionSequence(const ImplicitConversionSequence &Other) + : ConversionKind(Other.ConversionKind) + { + switch (ConversionKind) { + case StandardConversion: Standard = Other.Standard; break; + case UserDefinedConversion: UserDefined = Other.UserDefined; break; + case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; + case EllipsisConversion: break; + case BadConversion: break; + } + } + + ImplicitConversionSequence & + operator=(const ImplicitConversionSequence &Other) { + if (isAmbiguous()) Ambiguous.destruct(); + new (this) ImplicitConversionSequence(Other); + return *this; + } - /// When ConversionKind == BadConversion due to multiple conversion - /// functions, this will list those functions. - llvm::SmallVector ConversionFunctionSet; - + Kind getKind() const { return ConversionKind; } + bool isBad() const { return ConversionKind == BadConversion; } + bool isStandard() const { return ConversionKind == StandardConversion; } + bool isEllipsis() const { return ConversionKind == EllipsisConversion; } + bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; } + bool isUserDefined() const { + return ConversionKind == UserDefinedConversion; + } + + void setBad() { setKind(BadConversion); } + void setStandard() { setKind(StandardConversion); } + void setEllipsis() { setKind(EllipsisConversion); } + void setUserDefined() { setKind(UserDefinedConversion); } + void setAmbiguous() { + if (isAmbiguous()) return; + ConversionKind = AmbiguousConversion; + Ambiguous.construct(); + } + // The result of a comparison between implicit conversion // sequences. Use Sema::CompareImplicitConversionSequences to // actually perform the comparison. @@ -280,6 +381,16 @@ namespace clang { /// after the call to the overload candidate to convert the result /// of calling the conversion function to the required type. StandardConversionSequence FinalConversion; + + /// hasAmbiguousConversion - Returns whether this overload + /// candidate requires an ambiguous conversion or not. + bool hasAmbiguousConversion() const { + for (llvm::SmallVectorImpl::const_iterator + I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + if (I->isAmbiguous()) return true; + } + return false; + } }; /// OverloadCandidateSet - A set of overload candidates, used in C++ diff --git a/test/SemaCXX/ambig-user-defined-conversions.cpp b/test/SemaCXX/ambig-user-defined-conversions.cpp index 8ac822fc08..5e0a2e3766 100644 --- a/test/SemaCXX/ambig-user-defined-conversions.cpp +++ b/test/SemaCXX/ambig-user-defined-conversions.cpp @@ -21,6 +21,13 @@ namespace test0 { func(b1, f()); // expected-error {{call to 'func' is ambiguous}} return f(); // expected-error {{conversion from 'struct test0::B' to 'int const' is ambiguous}} } + + // This used to crash when comparing the two operands. + void func2(const char cc); // expected-note {{candidate function}} + void func2(const int ci); // expected-note {{candidate function}} + void Test2() { + func2(b1); // expected-error {{call to 'func2' is ambiguous}} + } } namespace test1 { diff --git a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp index 137503b2a4..b1b0b98b3c 100644 --- a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp +++ b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp @@ -40,7 +40,7 @@ void foo1(C1 c1, int A::* pmf) { } void foo1(C1 c1, int E::* pmf) { - // FIXME. Error reporting needs much improvement here. - int i = c1->*pmf; // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1'}} \ - // expected-note {{because of ambiguity in conversion of 'struct C1' to 'struct E *'}} + int i = c1->*pmf; // expected-error {{use of overloaded operator '->*' is ambiguous}} \ + // expected-note {{because of ambiguity in conversion of 'struct C1' to 'struct E *'}} \ + // expected-note 4 {{built-in candidate operator}} } diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index 0617cd5702..8eaff784da 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -7,8 +7,8 @@ struct ToBool { explicit operator bool(); }; struct B; -struct A { A(); A(const B&); }; -struct B { operator A() const; }; +struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} +struct B { operator A() const; }; // expected-note 2 {{candidate function}} struct I { operator int(); }; struct J { operator I(); }; struct K { operator double(); }; @@ -50,8 +50,8 @@ struct MixedFieldsDerived : MixedFields { enum Enum { EVal }; struct Ambig { - operator short(); - operator signed char(); + operator short(); // expected-note 2 {{candidate function}} + operator signed char(); // expected-note 2 {{candidate function}} }; void test() @@ -129,10 +129,10 @@ void test() vfn pfn = i1 ? F() : test; pfn = i1 ? test : F(); // these are ambiguous - better messages would be nice - (void)(i1 ? A() : B()); // expected-error {{incompatible operand types}} - (void)(i1 ? B() : A()); // expected-error {{incompatible operand types}} - (void)(i1 ? 1 : Ambig()); // expected-error {{incompatible operand types}} - (void)(i1 ? Ambig() : 1); // expected-error {{incompatible operand types}} + (void)(i1 ? A() : B()); // expected-error {{conversion from 'struct B' to 'struct A' is ambiguous}} + (void)(i1 ? B() : A()); // expected-error {{conversion from 'struct B' to 'struct A' is ambiguous}} + (void)(i1 ? 1 : Ambig()); // expected-error {{conversion from 'struct Ambig' to 'int' is ambiguous}} + (void)(i1 ? Ambig() : 1); // expected-error {{conversion from 'struct Ambig' to 'int' is ambiguous}} // By the way, this isn't an lvalue: &(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}