зеркало из https://github.com/microsoft/clang.git
Standard conversion sequences now have a CopyConstructor field, to
cope with the case where a user-defined conversion is actually a copy construction, and therefore can be compared against other standard conversion sequences. While I called this a hack before, now I'm convinced that it's the right way to go. Compare overloads based on derived-to-base conversions that invoke copy constructors. Suppress user-defined conversions when attempting to call a user-defined conversion. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58629 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
396b7cd9f6
Коммит
225c41eb3e
|
@ -370,7 +370,9 @@ private:
|
|||
/// C++ Overloading.
|
||||
bool IsOverload(FunctionDecl *New, Decl* OldD,
|
||||
OverloadedFunctionDecl::function_iterator &MatchedDecl);
|
||||
ImplicitConversionSequence TryImplicitConversion(Expr* From, QualType ToType);
|
||||
ImplicitConversionSequence
|
||||
TryImplicitConversion(Expr* From, QualType ToType,
|
||||
bool SuppressUserConversions = false);
|
||||
bool IsStandardConversion(Expr *From, QualType ToType,
|
||||
StandardConversionSequence& SCS);
|
||||
bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
|
||||
|
@ -398,7 +400,9 @@ private:
|
|||
CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
|
||||
const StandardConversionSequence& SCS2);
|
||||
|
||||
ImplicitConversionSequence TryCopyInitialization(Expr* From, QualType ToType);
|
||||
ImplicitConversionSequence
|
||||
TryCopyInitialization(Expr* From, QualType ToType,
|
||||
bool SuppressUserConversions = false);
|
||||
bool PerformCopyInitialization(Expr *&From, QualType ToType,
|
||||
const char *Flavor);
|
||||
|
||||
|
@ -412,10 +416,12 @@ private:
|
|||
|
||||
void AddOverloadCandidate(FunctionDecl *Function,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet);
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false);
|
||||
void AddOverloadCandidates(OverloadedFunctionDecl *Ovl,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet);
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false);
|
||||
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
|
||||
const OverloadCandidate& Cand2);
|
||||
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
|
||||
|
@ -1165,7 +1171,8 @@ private:
|
|||
bool& DerivedToBase);
|
||||
|
||||
bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
|
||||
ImplicitConversionSequence *ICS = 0);
|
||||
ImplicitConversionSequence *ICS = 0,
|
||||
bool SuppressUserConversions = false);
|
||||
|
||||
/// CheckCastTypes - Check type constraints for casting between types.
|
||||
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
|
||||
|
|
|
@ -931,9 +931,13 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
|
|||
/// errors are found. Either way, a return value of true indicates
|
||||
/// that there was a failure, a return value of false indicates that
|
||||
/// the reference initialization succeeded.
|
||||
///
|
||||
/// When @p SuppressUserConversions, user-defined conversions are
|
||||
/// suppressed.
|
||||
bool
|
||||
Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
|
||||
ImplicitConversionSequence *ICS) {
|
||||
ImplicitConversionSequence *ICS,
|
||||
bool SuppressUserConversions) {
|
||||
assert(DeclType->isReferenceType() && "Reference init needs a reference");
|
||||
|
||||
QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
|
||||
|
@ -1114,7 +1118,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
|
|||
/// the argument expression. Any difference in top-level
|
||||
/// cv-qualification is subsumed by the initialization itself
|
||||
/// and does not constitute a conversion.
|
||||
*ICS = TryImplicitConversion(Init, T1);
|
||||
*ICS = TryImplicitConversion(Init, T1, SuppressUserConversions);
|
||||
return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
|
||||
} else {
|
||||
return PerformImplicitConversion(Init, T1);
|
||||
|
|
|
@ -929,6 +929,13 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
|||
// anything here.
|
||||
QualType FromType = From->getType();
|
||||
|
||||
if (SCS.CopyConstructor) {
|
||||
// FIXME: Create a temporary object by calling the copy
|
||||
// constructor.
|
||||
ImpCastExprToType(From, ToType);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perform the first implicit conversion.
|
||||
switch (SCS.First) {
|
||||
case ICK_Identity:
|
||||
|
@ -982,13 +989,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
|||
ImpCastExprToType(From, FromType);
|
||||
break;
|
||||
|
||||
case ICK_Derived_To_Base:
|
||||
// FIXME: This should never happen. It's a consequence of
|
||||
// pretending that a user-defined conversion via copy constructor
|
||||
// is actually a standard conversion.
|
||||
ImpCastExprToType(From, ToType);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false && "Improper second standard conversion");
|
||||
break;
|
||||
|
|
|
@ -99,6 +99,7 @@ void StandardConversionSequence::setAsIdentityConversion() {
|
|||
Deprecated = false;
|
||||
ReferenceBinding = false;
|
||||
DirectBinding = false;
|
||||
CopyConstructor = 0;
|
||||
}
|
||||
|
||||
/// getRank - Retrieve the rank of this standard conversion sequence
|
||||
|
@ -174,6 +175,14 @@ void StandardConversionSequence::DebugPrint() const {
|
|||
fprintf(stderr, " -> ");
|
||||
}
|
||||
fprintf(stderr, "%s", GetImplicitConversionName(Second));
|
||||
|
||||
if (CopyConstructor) {
|
||||
fprintf(stderr, " (by copy constructor)");
|
||||
} else if (DirectBinding) {
|
||||
fprintf(stderr, " (direct reference binding)");
|
||||
} else if (ReferenceBinding) {
|
||||
fprintf(stderr, " (reference binding)");
|
||||
}
|
||||
PrintedSomething = true;
|
||||
}
|
||||
|
||||
|
@ -344,13 +353,18 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
|
|||
/// it will not produce any diagnostics if no conversion is available,
|
||||
/// but will instead return an implicit conversion sequence of kind
|
||||
/// "BadConversion".
|
||||
///
|
||||
/// If @p SuppressUserConversions, then user-defined conversions are
|
||||
/// not permitted.
|
||||
ImplicitConversionSequence
|
||||
Sema::TryImplicitConversion(Expr* From, QualType ToType)
|
||||
Sema::TryImplicitConversion(Expr* From, QualType ToType,
|
||||
bool SuppressUserConversions)
|
||||
{
|
||||
ImplicitConversionSequence ICS;
|
||||
if (IsStandardConversion(From, ToType, ICS.Standard))
|
||||
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||
else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
|
||||
else if (!SuppressUserConversions &&
|
||||
IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
|
||||
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
|
||||
// C++ [over.ics.user]p4:
|
||||
// A conversion of an expression of class type to the same class
|
||||
|
@ -362,15 +376,13 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType)
|
|||
if (CXXConstructorDecl *Constructor
|
||||
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
|
||||
if (Constructor->isCopyConstructor(Context)) {
|
||||
// FIXME: This is a temporary hack to give copy-constructor
|
||||
// calls the appropriate rank (Exact Match or Conversion) by
|
||||
// making them into standard conversions. To really fix this, we
|
||||
// need to tweak the rank-checking logic to deal with ranking
|
||||
// different kinds of user conversions.
|
||||
// Turn this into a "standard" conversion sequence, so that it
|
||||
// gets ranked with standard conversion sequences.
|
||||
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||
ICS.Standard.setAsIdentityConversion();
|
||||
ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
|
||||
ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
|
||||
ICS.Standard.CopyConstructor = Constructor;
|
||||
if (IsDerivedFrom(From->getType().getUnqualifiedType(),
|
||||
ToType.getUnqualifiedType()))
|
||||
ICS.Standard.Second = ICK_Derived_To_Base;
|
||||
|
@ -403,6 +415,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
|
|||
// Standard conversions (C++ [conv])
|
||||
SCS.Deprecated = false;
|
||||
SCS.FromTypePtr = FromType.getAsOpaquePtr();
|
||||
SCS.CopyConstructor = 0;
|
||||
|
||||
// The first conversion can be an lvalue-to-rvalue conversion,
|
||||
// array-to-pointer conversion, or function-to-pointer conversion
|
||||
|
@ -536,13 +549,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
|
|||
// [...] Any difference in top-level cv-qualification is
|
||||
// subsumed by the initialization itself and does not constitute
|
||||
// a conversion. [...]
|
||||
|
||||
// C++ [dcl.init]p14 last bullet:
|
||||
// [ Note: an expression of type "cv1 T" can initialize an object
|
||||
// of type “cv2 T” independently of the cv-qualifiers cv1 and
|
||||
// cv2. -- end note]
|
||||
//
|
||||
// FIXME: Where is the normative text?
|
||||
CanonFrom = Context.getCanonicalType(FromType);
|
||||
CanonTo = Context.getCanonicalType(ToType);
|
||||
if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
|
||||
|
@ -881,8 +887,8 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
|
|||
func != Constructors->function_end(); ++func) {
|
||||
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*func);
|
||||
if (Constructor->isConvertingConstructor())
|
||||
// FIXME: Suppress user-defined conversions in here!
|
||||
AddOverloadCandidate(Constructor, &From, 1, CandidateSet);
|
||||
AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
|
||||
/*SuppressUserConversions=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1259,9 +1265,9 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
|
|||
return ImplicitConversionSequence::Worse;
|
||||
}
|
||||
|
||||
// -- binding of an expression of type B to a reference of type
|
||||
// A& is better than binding an expression of type C to a
|
||||
// reference of type A&,
|
||||
// -- binding of an expression of type B to a reference of type
|
||||
// A& is better than binding an expression of type C to a
|
||||
// reference of type A&,
|
||||
if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
|
||||
ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
|
||||
if (IsDerivedFrom(FromType2, FromType1))
|
||||
|
@ -1278,9 +1284,26 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
|
|||
// FIXME: conversion of B::* to C::* is better than conversion of
|
||||
// A::* to C::*, and
|
||||
|
||||
// FIXME: conversion of C to B is better than conversion of C to A,
|
||||
if (SCS1.CopyConstructor && SCS2.CopyConstructor &&
|
||||
SCS1.Second == ICK_Derived_To_Base) {
|
||||
// -- conversion of C to B is better than conversion of C to A,
|
||||
if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
|
||||
ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
|
||||
if (IsDerivedFrom(ToType1, ToType2))
|
||||
return ImplicitConversionSequence::Better;
|
||||
else if (IsDerivedFrom(ToType2, ToType1))
|
||||
return ImplicitConversionSequence::Worse;
|
||||
}
|
||||
|
||||
// FIXME: conversion of B to A is better than conversion of C to A.
|
||||
// -- conversion of B to A is better than conversion of C to A.
|
||||
if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
|
||||
ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
|
||||
if (IsDerivedFrom(FromType2, FromType1))
|
||||
return ImplicitConversionSequence::Better;
|
||||
else if (IsDerivedFrom(FromType1, FromType2))
|
||||
return ImplicitConversionSequence::Worse;
|
||||
}
|
||||
}
|
||||
|
||||
return ImplicitConversionSequence::Indistinguishable;
|
||||
}
|
||||
|
@ -1289,9 +1312,11 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
|
|||
/// ToType from the expression From. Return the implicit conversion
|
||||
/// sequence required to pass this argument, which may be a bad
|
||||
/// conversion sequence (meaning that the argument cannot be passed to
|
||||
/// a parameter of this type). This is user for argument passing,
|
||||
/// a parameter of this type). If @p SuppressUserConversions, then we
|
||||
/// do not permit any user-defined conversion sequences.
|
||||
ImplicitConversionSequence
|
||||
Sema::TryCopyInitialization(Expr *From, QualType ToType) {
|
||||
Sema::TryCopyInitialization(Expr *From, QualType ToType,
|
||||
bool SuppressUserConversions) {
|
||||
if (!getLangOptions().CPlusPlus) {
|
||||
// In C, copy initialization is the same as performing an assignment.
|
||||
AssignConvertType ConvTy =
|
||||
|
@ -1305,10 +1330,10 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType) {
|
|||
return ICS;
|
||||
} else if (ToType->isReferenceType()) {
|
||||
ImplicitConversionSequence ICS;
|
||||
CheckReferenceInit(From, ToType, &ICS);
|
||||
CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions);
|
||||
return ICS;
|
||||
} else {
|
||||
return TryImplicitConversion(From, ToType);
|
||||
return TryImplicitConversion(From, ToType, SuppressUserConversions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1340,11 +1365,14 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
|
|||
}
|
||||
|
||||
/// AddOverloadCandidate - Adds the given function to the set of
|
||||
/// candidate functions, using the given function call arguments.
|
||||
/// candidate functions, using the given function call arguments. If
|
||||
/// @p SuppressUserConversions, then don't allow user-defined
|
||||
/// conversions via constructors or conversion operators.
|
||||
void
|
||||
Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet)
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions)
|
||||
{
|
||||
const FunctionTypeProto* Proto
|
||||
= dyn_cast<FunctionTypeProto>(Function->getType()->getAsFunctionType());
|
||||
|
@ -1389,7 +1417,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
|||
// parameter of F.
|
||||
QualType ParamType = Proto->getArgType(ArgIdx);
|
||||
Candidate.Conversions[ArgIdx]
|
||||
= TryCopyInitialization(Args[ArgIdx], ParamType);
|
||||
= TryCopyInitialization(Args[ArgIdx], ParamType,
|
||||
SuppressUserConversions);
|
||||
if (Candidate.Conversions[ArgIdx].ConversionKind
|
||||
== ImplicitConversionSequence::BadConversion)
|
||||
Candidate.Viable = false;
|
||||
|
@ -1408,11 +1437,13 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
|||
void
|
||||
Sema::AddOverloadCandidates(OverloadedFunctionDecl *Ovl,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet)
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions)
|
||||
{
|
||||
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin();
|
||||
Func != Ovl->function_end(); ++Func)
|
||||
AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
|
||||
AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
}
|
||||
|
||||
/// isBetterOverloadCandidate - Determines whether the first overload
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
class CXXConstructorDecl;
|
||||
class FunctionDecl;
|
||||
|
||||
/// ImplicitConversionKind - The kind of implicit conversion used to
|
||||
|
@ -114,6 +115,13 @@ namespace clang {
|
|||
/// is an opaque pointer that can be translated into a QualType.
|
||||
void *ToTypePtr;
|
||||
|
||||
/// CopyConstructor - The copy constructor that is used to perform
|
||||
/// this conversion, when the conversion is actually just the
|
||||
/// initialization of an object via copy constructor. Such
|
||||
/// conversions are either identity conversions or derived-to-base
|
||||
/// conversions.
|
||||
CXXConstructorDecl *CopyConstructor;
|
||||
|
||||
void setAsIdentityConversion();
|
||||
ImplicitConversionRank getRank() const;
|
||||
bool isPointerConversionToBool() const;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang -fsyntax-only %s
|
||||
// RUN: clang -fsyntax-only -verify %s
|
||||
class Z { };
|
||||
|
||||
class Y {
|
||||
|
@ -18,6 +18,6 @@ void g(short s, Y y, Z z) {
|
|||
f(s);
|
||||
f(1.0f);
|
||||
f(y);
|
||||
f(z); // expected-error{{incompatible}}
|
||||
f(z); // expected-error{{incompatible type passing 'class Z', expected 'class X'}}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,3 +36,13 @@ void test_copycon3(B b, const B bc) {
|
|||
int& i1 = copycon3(b);
|
||||
float& f1 = copycon3(bc);
|
||||
}
|
||||
|
||||
|
||||
class C : public B { };
|
||||
|
||||
float& copycon4(A a);
|
||||
int& copycon4(B b);
|
||||
|
||||
void test_copycon4(C c) {
|
||||
int& i = copycon4(c);
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче