r183637 - reverted test
Larisse Voufo
lvoufo at google.com
Sun Jun 9 23:50:24 PDT 2013
Author: lvoufo
Date: Mon Jun 10 01:50:24 2013
New Revision: 183637
URL: http://llvm.org/viewvc/llvm-project?rev=183637&view=rev
Log:
reverted test
Added:
cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
Modified:
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=183637&r1=183636&r2=183637&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jun 10 01:50:24 2013
@@ -5121,6 +5121,130 @@ bool Sema::ICEConvertDiagnoser::match(Qu
: 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<CXXConversionDecl>(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<CXXConversionDecl>(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<CXXConversionDecl>(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<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ CXXConversionDecl *Conv;
+ FunctionTemplateDecl *ConvTemplate;
+ if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(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::PerformContextualImplic
// 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::PerformContextualImplic
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<CXXRecordDecl::conversion_iterator,
- CXXRecordDecl::conversion_iterator> Conversions
- = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+ CXXRecordDecl::conversion_iterator> Conversions =
+ cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
- bool HadMultipleCandidates
- = (std::distance(Conversions.first, Conversions.second) > 1);
+ bool HadMultipleCandidates =
+ (std::distance(Conversions.first, Conversions.second) > 1);
- for (CXXRecordDecl::conversion_iterator
- I = Conversions.first, E = Conversions.second; I != E; ++I) {
- if (CXXConversionDecl *Conversion
- = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
- if (Converter.match(
- Conversion->getConversionType().getNonReferenceType())) {
- if (Conversion->isExplicit())
+ // 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<FunctionTemplateDecl>(D);
+ if (ConvTemplate) {
+ if (getLangOpts().CPlusPlus1y)
+ Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ continue; // C++11 does not consider conversion operator templates(?).
+ } else
+ Conversion = cast<CXXConversionDecl>(D);
+
+ assert((!ConvTemplate || getLangOpts().CPlusPlus1y) &&
+ "Conversion operator templates are considered potentially "
+ "viable in C++1y");
+
+ 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<CXXConversionDecl>(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, getPrintingPolicy());
-
- 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 we aren't in a SFINAE context, build a call to the
- // explicit conversion function.
- if (isSFINAEContext())
+ 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.
+
+ // 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);
+ }
- CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
- ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion,
- HadMultipleCandidates);
- if (Result.isInvalid())
+ // If more than one unique Ts are found:
+ if (!HasUniqueTargetType)
+ return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
+ ViableConversions);
+
+ // 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);
+
+ // 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());
- }
-
- // 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<CXXConversionDecl>(Found->getUnderlyingDecl());
- QualType ConvTy
- = Conversion->getConversionType().getNonReferenceType();
- if (!Converter.SuppressConversion) {
- if (isSFINAEContext())
+ break;
+ }
+ 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<CXXConversionDecl>(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
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=183637&r1=183636&r2=183637&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jun 10 01:50:24 2013
@@ -2842,7 +2842,6 @@ void Sema::InstantiateFunctionDefinition
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 &&
Added: cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp?rev=183637&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp Mon Jun 10 01:50:24 2013
@@ -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 T> class zero_init {
+ public:
+ zero_init() : val(static_cast<T>(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<int *> p;
+ p = new int(7);
+ delete p; //@23
+ delete (p + 0);
+ delete + p;
+ }
+
+ void Switch() {
+ zero_init<int> i;
+ i = 7;
+ switch (i) {} // @31
+ switch (i + 0) {}
+ switch (+i) {}
+ }
+}
+
+#ifdef CXX1Y
+#else
+//expected-error at 23 {{ambiguous conversion of delete expression of type 'zero_init<int *>' to a pointer}}
+//expected-note at 13 {{conversion to pointer type 'int *'}}
+//expected-note at 14 {{conversion to pointer type 'int *'}}
+//expected-error at 31 {{multiple conversions from switch condition type 'zero_init<int>' to an integral or enumeration type}}
+//expected-note at 13 {{conversion to integral type 'int'}}
+//expected-note at 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<typename T> operator T(); // not matching (ambiguous anyway)
+ };
+
+ struct A4 {
+ template<typename T> 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 at 71 {{cannot overload a member function without a ref-qualifier with a member function with ref-qualifier '&&'}}
+//expected-note at 70 {{previous declaration is here}}
+//expected-error at 82 {{statement requires expression of integer type ('extended_examples::A2' invalid)}}
+//expected-error at 83 {{statement requires expression of integer type ('extended_examples::A3' invalid)}}
+//expected-error at 84 {{statement requires expression of integer type ('extended_examples::A4' invalid)}}
+
+#ifdef CXX1Y
+//expected-error at 81 {{statement requires expression of integer type ('extended_examples::A1' invalid)}}
+//expected-error at 85 {{statement requires expression of integer type ('extended_examples::B2' invalid)}}
+#else
+//expected-error at 81 {{cannot initialize object parameter of type 'extended_examples::A1' with an expression of type 'extended_examples::A1'}}
+//expected-error at 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 at 142 {{statement requires expression of integer type ('extended_examples_cxx1y::C' invalid)}}
+
+#ifdef CXX1Y
+//expected-error at 139 {{statement requires expression of integer type ('extended_examples_cxx1y::A2' invalid)}}
+#else
+//expected-error at 138 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A1' with an expression of type 'extended_examples_cxx1y::A1'}}
+//expected-error at 139 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A2' with an expression of type 'extended_examples_cxx1y::A2'}}
+//expected-error at 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].
More information about the cfe-commits
mailing list