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
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index fa87479..1b08a45 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -370,7 +370,9 @@
/// 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 @@
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 @@
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 @@
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);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 7035223..1100e70 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -931,9 +931,13 @@
/// 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 @@
/// 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);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 99b0829..fde2852 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -929,6 +929,13 @@
// 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 @@
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;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b20c026..1c2f20b 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -99,6 +99,7 @@
Deprecated = false;
ReferenceBinding = false;
DirectBinding = false;
+ CopyConstructor = 0;
}
/// getRank - Retrieve the rank of this standard conversion sequence
@@ -174,6 +175,14 @@
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 @@
/// 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 @@
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 @@
// 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 @@
// [...] 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 @@
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 @@
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 @@
// 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 @@
/// 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 @@
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 @@
}
/// 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 @@
// 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 @@
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
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 2fd6b1f..af3d1b4 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -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 @@
/// 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;
diff --git a/test/SemaCXX/converting-constructor.cpp b/test/SemaCXX/converting-constructor.cpp
index 4bcd5aa..b99a134 100644
--- a/test/SemaCXX/converting-constructor.cpp
+++ b/test/SemaCXX/converting-constructor.cpp
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only %s
+// RUN: clang -fsyntax-only -verify %s
class Z { };
class Y {
@@ -18,6 +18,6 @@
f(s);
f(1.0f);
f(y);
- f(z); // expected-error{{incompatible}}
+ f(z); // expected-error{{incompatible type passing 'class Z', expected 'class X'}}
}
diff --git a/test/SemaCXX/overload-call-copycon.cpp b/test/SemaCXX/overload-call-copycon.cpp
index 8270928..281f4ce 100644
--- a/test/SemaCXX/overload-call-copycon.cpp
+++ b/test/SemaCXX/overload-call-copycon.cpp
@@ -36,3 +36,13 @@
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);
+};