From 236bec24ec195a47344392222c9ee69e12e8982d Mon Sep 17 00:00:00 2001 From: Larisse Voufo Date: Mon, 10 Jun 2013 06:50:24 +0000 Subject: [PATCH] reverted test llvm-svn: 183637 --- clang/lib/Sema/SemaOverload.cpp | 334 +++++++++++++----- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 1 - .../cxx1y-contextual-conversion-tweaks.cpp | 157 ++++++++ 3 files changed, 398 insertions(+), 94 deletions(-) create mode 100644 clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 034790db20e3..0653fbea54af 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5121,6 +5121,130 @@ bool Sema::ICEConvertDiagnoser::match(QualType T) { : T->isIntegralOrUnscopedEnumerationType(); } +static ExprResult +diagnoseAmbiguousConversion(Sema &SemaRef, SourceLocation Loc, Expr *From, + Sema::ContextualImplicitConverter &Converter, + QualType T, UnresolvedSetImpl &ViableConversions) { + + if (Converter.Suppress) + return ExprError(); + + Converter.diagnoseAmbiguous(SemaRef, Loc, T) << From->getSourceRange(); + for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { + CXXConversionDecl *Conv = + cast(ViableConversions[I]->getUnderlyingDecl()); + QualType ConvTy = Conv->getConversionType().getNonReferenceType(); + Converter.noteAmbiguous(SemaRef, Conv, ConvTy); + } + return SemaRef.Owned(From); +} + +static bool +diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From, + Sema::ContextualImplicitConverter &Converter, + QualType T, bool HadMultipleCandidates, + UnresolvedSetImpl &ExplicitConversions) { + if (ExplicitConversions.size() == 1 && !Converter.Suppress) { + DeclAccessPair Found = ExplicitConversions[0]; + CXXConversionDecl *Conversion = + cast(Found->getUnderlyingDecl()); + + // The user probably meant to invoke the given explicit + // conversion; use it. + QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); + std::string TypeStr; + ConvTy.getAsStringInternal(TypeStr, SemaRef.getPrintingPolicy()); + + Converter.diagnoseExplicitConv(SemaRef, Loc, T, ConvTy) + << FixItHint::CreateInsertion(From->getLocStart(), + "static_cast<" + TypeStr + ">(") + << FixItHint::CreateInsertion( + SemaRef.PP.getLocForEndOfToken(From->getLocEnd()), ")"); + Converter.noteExplicitConv(SemaRef, Conversion, ConvTy); + + // If we aren't in a SFINAE context, build a call to the + // explicit conversion function. + if (SemaRef.isSFINAEContext()) + return true; + + SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); + ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion, + HadMultipleCandidates); + if (Result.isInvalid()) + return true; + // Record usage of conversion in an implicit cast. + From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(), + CK_UserDefinedConversion, Result.get(), 0, + Result.get()->getValueKind()); + } + return false; +} + +static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From, + Sema::ContextualImplicitConverter &Converter, + QualType T, bool HadMultipleCandidates, + DeclAccessPair &Found) { + CXXConversionDecl *Conversion = + cast(Found->getUnderlyingDecl()); + SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); + + QualType ToType = Conversion->getConversionType().getNonReferenceType(); + if (!Converter.SuppressConversion) { + if (SemaRef.isSFINAEContext()) + return true; + + Converter.diagnoseConversion(SemaRef, Loc, T, ToType) + << From->getSourceRange(); + } + + ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion, + HadMultipleCandidates); + if (Result.isInvalid()) + return true; + // Record usage of conversion in an implicit cast. + From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(), + CK_UserDefinedConversion, Result.get(), 0, + Result.get()->getValueKind()); + return false; +} + +static ExprResult finishContextualImplicitConversion( + Sema &SemaRef, SourceLocation Loc, Expr *From, + Sema::ContextualImplicitConverter &Converter) { + if (!Converter.match(From->getType()) && !Converter.Suppress) + Converter.diagnoseNoMatch(SemaRef, Loc, From->getType()) + << From->getSourceRange(); + + return SemaRef.DefaultLvalueConversion(From); +} + +static void +collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType, + UnresolvedSetImpl &ViableConversions, + OverloadCandidateSet &CandidateSet) { + for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { + DeclAccessPair FoundDecl = ViableConversions[I]; + NamedDecl *D = FoundDecl.getDecl(); + CXXRecordDecl *ActingContext = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + if ((ConvTemplate = dyn_cast(D))) + Conv = cast(ConvTemplate->getTemplatedDecl()); + else + Conv = cast(D); + + if (ConvTemplate) + SemaRef.AddTemplateConversionCandidate( + ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet); + else + SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From, + ToType, CandidateSet); + } +} + /// \brief Attempt to convert the given expression to a type which is accepted /// by the given converter. /// @@ -5148,7 +5272,8 @@ ExprResult Sema::PerformContextualImplicitConversion( // Process placeholders immediately. if (From->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(From); - if (result.isInvalid()) return result; + if (result.isInvalid()) + return result; From = result.take(); } @@ -5185,119 +5310,142 @@ ExprResult Sema::PerformContextualImplicitConversion( return Owned(From); // Look for a conversion to an integral or enumeration type. - UnresolvedSet<4> ViableConversions; + UnresolvedSet<4> + ViableConversions; // These are *potentially* viable in C++1y. UnresolvedSet<4> ExplicitConversions; std::pair Conversions - = cast(RecordTy->getDecl())->getVisibleConversionFunctions(); + CXXRecordDecl::conversion_iterator> Conversions = + cast(RecordTy->getDecl())->getVisibleConversionFunctions(); + + bool HadMultipleCandidates = + (std::distance(Conversions.first, Conversions.second) > 1); + + // To check that there is only one target type, in C++1y: + QualType ToType; + bool HasUniqueTargetType = true; + + // Collect explicit or viable (potentially in C++1y) conversions. + for (CXXRecordDecl::conversion_iterator I = Conversions.first, + E = Conversions.second; + I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + CXXConversionDecl *Conversion; + FunctionTemplateDecl *ConvTemplate = dyn_cast(D); + if (ConvTemplate) { + if (getLangOpts().CPlusPlus1y) + Conversion = cast(ConvTemplate->getTemplatedDecl()); + else + continue; // C++11 does not consider conversion operator templates(?). + } else + Conversion = cast(D); - bool HadMultipleCandidates - = (std::distance(Conversions.first, Conversions.second) > 1); + assert((!ConvTemplate || getLangOpts().CPlusPlus1y) && + "Conversion operator templates are considered potentially " + "viable in C++1y"); - for (CXXRecordDecl::conversion_iterator - I = Conversions.first, E = Conversions.second; I != E; ++I) { - if (CXXConversionDecl *Conversion - = dyn_cast((*I)->getUnderlyingDecl())) { - if (Converter.match( - Conversion->getConversionType().getNonReferenceType())) { - if (Conversion->isExplicit()) + QualType CurToType = Conversion->getConversionType().getNonReferenceType(); + if (Converter.match(CurToType) || ConvTemplate) { + + if (Conversion->isExplicit()) { + // FIXME: For C++1y, do we need this restriction? + // cf. diagnoseNoViableConversion() + if (!ConvTemplate) ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); - else - ViableConversions.addDecl(I.getDecl(), I.getAccess()); + } else { + if (!ConvTemplate && getLangOpts().CPlusPlus1y) { + if (ToType.isNull()) + ToType = CurToType.getUnqualifiedType(); + else if (HasUniqueTargetType && + (CurToType.getUnqualifiedType() != ToType)) + HasUniqueTargetType = false; + } + ViableConversions.addDecl(I.getDecl(), I.getAccess()); } } } - // FIXME: Implement the C++11 rules! - switch (ViableConversions.size()) { - case 0: - if (ExplicitConversions.size() == 1 && !Converter.Suppress) { - DeclAccessPair Found = ExplicitConversions[0]; - CXXConversionDecl *Conversion - = cast(Found->getUnderlyingDecl()); + if (getLangOpts().CPlusPlus1y) { + // C++1y [conv]p6: + // ... An expression e of class type E appearing in such a context + // is said to be contextually implicitly converted to a specified + // type T and is well-formed if and only if e can be implicitly + // converted to a type T that is determined as follows: E is searched + // for conversion functions whose return type is cv T or reference + // to cv T such that T is allowed by the context. There shall be + // exactly one such T. - // The user probably meant to invoke the given explicit - // conversion; use it. - QualType ConvTy - = Conversion->getConversionType().getNonReferenceType(); - std::string TypeStr; - ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy()); + // If no unique T is found: + if (ToType.isNull()) { + if (diagnoseNoViableConversion(*this, Loc, From, Converter, T, + HadMultipleCandidates, + ExplicitConversions)) + return ExprError(); + return finishContextualImplicitConversion(*this, Loc, From, Converter); + } - Converter.diagnoseExplicitConv(*this, Loc, T, ConvTy) - << FixItHint::CreateInsertion(From->getLocStart(), - "static_cast<" + TypeStr + ">(") - << FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()), - ")"); - Converter.noteExplicitConv(*this, Conversion, ConvTy); + // If more than one unique Ts are found: + if (!HasUniqueTargetType) + return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T, + ViableConversions); - // If we aren't in a SFINAE context, build a call to the - // explicit conversion function. - if (isSFINAEContext()) - return ExprError(); + // If one unique T is found: + // First, build a candidate set from the previously recorded + // potentially viable conversions. + OverloadCandidateSet CandidateSet(Loc); + collectViableConversionCandidates(*this, From, ToType, ViableConversions, + CandidateSet); - CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion, - HadMultipleCandidates); - if (Result.isInvalid()) + // Then, perform overload resolution over the candidate set. + OverloadCandidateSet::iterator Best; + switch (CandidateSet.BestViableFunction(*this, Loc, Best)) { + case OR_Success: { + // Apply this conversion. + DeclAccessPair Found = + DeclAccessPair::make(Best->Function, Best->FoundDecl.getAccess()); + if (recordConversion(*this, Loc, From, Converter, T, + HadMultipleCandidates, Found)) return ExprError(); - // Record usage of conversion in an implicit cast. - From = ImplicitCastExpr::Create(Context, Result.get()->getType(), - CK_UserDefinedConversion, - Result.get(), 0, - Result.get()->getValueKind()); + break; } - - // We'll complain below about a non-integral condition type. - break; - - case 1: { - // Apply this conversion. - DeclAccessPair Found = ViableConversions[0]; - CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - - CXXConversionDecl *Conversion - = cast(Found->getUnderlyingDecl()); - QualType ConvTy - = Conversion->getConversionType().getNonReferenceType(); - if (!Converter.SuppressConversion) { - if (isSFINAEContext()) + case OR_Ambiguous: + return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T, + ViableConversions); + case OR_No_Viable_Function: + if (diagnoseNoViableConversion(*this, Loc, From, Converter, T, + HadMultipleCandidates, + ExplicitConversions)) return ExprError(); - - Converter.diagnoseConversion(*this, Loc, T, ConvTy) - << From->getSourceRange(); + // fall through 'OR_Deleted' case. + case OR_Deleted: + // We'll complain below about a non-integral condition type. + break; } + } else { + switch (ViableConversions.size()) { + case 0: { + if (diagnoseNoViableConversion(*this, Loc, From, Converter, T, + HadMultipleCandidates, + ExplicitConversions)) + return ExprError(); - ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion, - HadMultipleCandidates); - if (Result.isInvalid()) - return ExprError(); - // Record usage of conversion in an implicit cast. - From = ImplicitCastExpr::Create(Context, Result.get()->getType(), - CK_UserDefinedConversion, - Result.get(), 0, - Result.get()->getValueKind()); - break; - } - - default: - if (Converter.Suppress) - return ExprError(); - - Converter.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange(); - for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { - CXXConversionDecl *Conv - = cast(ViableConversions[I]->getUnderlyingDecl()); - QualType ConvTy = Conv->getConversionType().getNonReferenceType(); - Converter.noteAmbiguous(*this, Conv, ConvTy); + // We'll complain below about a non-integral condition type. + break; + } + case 1: { + // Apply this conversion. + DeclAccessPair Found = ViableConversions[0]; + if (recordConversion(*this, Loc, From, Converter, T, + HadMultipleCandidates, Found)) + return ExprError(); + break; + } + default: + return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T, + ViableConversions); } - return Owned(From); } - if (!Converter.match(From->getType()) && !Converter.Suppress) - Converter.diagnoseNoMatch(*this, Loc, From->getType()) - << From->getSourceRange(); - - return DefaultLvalueConversion(From); + return finishContextualImplicitConversion(*this, Loc, From, Converter); } /// AddOverloadCandidate - Adds the given function to the set of diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 55915794f96a..9d1757d878d1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2842,7 +2842,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Function->isInvalidDecl() || Function->isDefined()) return; - // Never instantiate an explicit specialization except if it is a class scope // explicit specialization. if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && diff --git a/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp b/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp new file mode 100644 index 000000000000..f00bf1ea3104 --- /dev/null +++ b/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp @@ -0,0 +1,157 @@ +// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only %s +// RUN: %clang_cc1 -std=c++1y %s -verify -DCXX1Y + +// Explicit member declarations behave as in C++11. + +namespace n3323_example { + + template class zero_init { + public: + zero_init() : val(static_cast(0)) {} + zero_init(T val) : val(val) {} + + operator T &() { return val; } //@13 + operator T() const { return val; } //@14 + + private: + T val; + }; + + void Delete() { + zero_init p; + p = new int(7); + delete p; //@23 + delete (p + 0); + delete + p; + } + + void Switch() { + zero_init i; + i = 7; + switch (i) {} // @31 + switch (i + 0) {} + switch (+i) {} + } +} + +#ifdef CXX1Y +#else +//expected-error@23 {{ambiguous conversion of delete expression of type 'zero_init' to a pointer}} +//expected-note@13 {{conversion to pointer type 'int *'}} +//expected-note@14 {{conversion to pointer type 'int *'}} +//expected-error@31 {{multiple conversions from switch condition type 'zero_init' to an integral or enumeration type}} +//expected-note@13 {{conversion to integral type 'int'}} +//expected-note@14 {{conversion to integral type 'int'}} +#endif + +namespace extended_examples { + + struct A0 { + operator int(); // matching and viable + }; + + struct A1 { + operator int() &&; // matching and not viable + }; + + struct A2 { + operator float(); // not matching + }; + + struct A3 { + template operator T(); // not matching (ambiguous anyway) + }; + + struct A4 { + template operator int(); // not matching (ambiguous anyway) + }; + + struct B1 { + operator int() &&; // @70 + operator int(); // @71 -- duplicate declaration with different qualifier is not allowed + }; + + struct B2 { + operator int() &&; // matching but not viable + operator float(); // not matching + }; + + void foo(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, B2 b2) { + switch (a0) {} + switch (a1) {} // @81 -- fails for different reasons + switch (a2) {} // @82 + switch (a3) {} // @83 + switch (a4) {} // @84 + switch (b2) {} // @85 -- fails for different reasons + } +} + +//expected-error@71 {{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&&'}} +//expected-note@70 {{previous declaration is here}} +//expected-error@82 {{statement requires expression of integer type ('extended_examples::A2' invalid)}} +//expected-error@83 {{statement requires expression of integer type ('extended_examples::A3' invalid)}} +//expected-error@84 {{statement requires expression of integer type ('extended_examples::A4' invalid)}} + +#ifdef CXX1Y +//expected-error@81 {{statement requires expression of integer type ('extended_examples::A1' invalid)}} +//expected-error@85 {{statement requires expression of integer type ('extended_examples::B2' invalid)}} +#else +//expected-error@81 {{cannot initialize object parameter of type 'extended_examples::A1' with an expression of type 'extended_examples::A1'}} +//expected-error@85 {{cannot initialize object parameter of type 'extended_examples::B2' with an expression of type 'extended_examples::B2'}} +#endif + +namespace extended_examples_cxx1y { + + struct A1 { // leads to viable match in C++1y, and no viable match in C++11 + operator int() &&; // matching but not viable + template operator T(); // In C++1y: matching and viable, since disambiguated by L.100 + }; + + struct A2 { // leads to ambiguity in C++1y, and no viable match in C++11 + operator int() &&; // matching but not viable + template operator int(); // In C++1y: matching but ambiguous (disambiguated by L.105). + }; + + struct B1 { // leads to one viable match in both cases + operator int(); // matching and viable + template operator T(); // In C++1y: matching and viable, since disambiguated by L.110 + }; + + struct B2 { // leads to one viable match in both cases + operator int(); // matching and viable + template operator int(); // In C++1y: matching but ambiguous, since disambiguated by L.115 + }; + + struct C { // leads to no match in both cases + operator float(); // not matching + template operator T(); // In C++1y: not matching, nor viable. + }; + + struct D { // leads to viable match in C++1y, and no viable match in C++11 + operator int() &&; // matching but not viable + operator float(); // not matching + template operator T(); // In C++1y: matching and viable, since disambiguated by L.125 + }; + + + void foo(A1 a1, A2 a2, B1 b1, B2 b2, C c, D d) { + switch (a1) {} // @138 -- should presumably call templated conversion operator to convert to int. + switch (a2) {} // @139 + switch (b1) {} + switch (b2) {} + switch (c) {} // @142 + switch (d) {} // @143 + } +} + +//expected-error@142 {{statement requires expression of integer type ('extended_examples_cxx1y::C' invalid)}} + +#ifdef CXX1Y +//expected-error@139 {{statement requires expression of integer type ('extended_examples_cxx1y::A2' invalid)}} +#else +//expected-error@138 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A1' with an expression of type 'extended_examples_cxx1y::A1'}} +//expected-error@139 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A2' with an expression of type 'extended_examples_cxx1y::A2'}} +//expected-error@143 {{cannot initialize object parameter of type 'extended_examples_cxx1y::D' with an expression of type 'extended_examples_cxx1y::D'}} +#endif + +// FIXME: Extend with more examples, including [expr.const] and [expr.new]. -- 2.34.1