forked from OSchip/llvm-project
parent
ef2de6f255
commit
236bec24ec
|
@ -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<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::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<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());
|
||||
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());
|
||||
|
||||
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 no unique T is found:
|
||||
if (ToType.isNull()) {
|
||||
if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
|
||||
HadMultipleCandidates,
|
||||
ExplicitConversions))
|
||||
return ExprError();
|
||||
|
||||
CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
|
||||
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());
|
||||
return finishContextualImplicitConversion(*this, Loc, From, Converter);
|
||||
}
|
||||
|
||||
// We'll complain below about a non-integral condition type.
|
||||
break;
|
||||
// If more than one unique Ts are found:
|
||||
if (!HasUniqueTargetType)
|
||||
return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
|
||||
ViableConversions);
|
||||
|
||||
case 1: {
|
||||
// Apply this conversion.
|
||||
DeclAccessPair Found = ViableConversions[0];
|
||||
CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
|
||||
// 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);
|
||||
|
||||
CXXConversionDecl *Conversion
|
||||
= cast<CXXConversionDecl>(Found->getUnderlyingDecl());
|
||||
QualType ConvTy
|
||||
= Conversion->getConversionType().getNonReferenceType();
|
||||
if (!Converter.SuppressConversion) {
|
||||
if (isSFINAEContext())
|
||||
// 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();
|
||||
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();
|
||||
// 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();
|
||||
|
||||
Converter.diagnoseConversion(*this, Loc, T, ConvTy)
|
||||
<< From->getSourceRange();
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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@23 {{ambiguous conversion of delete expression of type 'zero_init<int *>' 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<int>' 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<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@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 <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@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].
|
Loading…
Reference in New Issue