reverted test

llvm-svn: 183637
This commit is contained in:
Larisse Voufo 2013-06-10 06:50:24 +00:00
parent ef2de6f255
commit 236bec24ec
3 changed files with 399 additions and 95 deletions

View File

@ -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

View File

@ -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 &&

View File

@ -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].