[cfe-commits] r110773 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaOverload.cpp test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp test/SemaCXX/conversion-function.cpp test/SemaCXX/overload-call-copycon.cpp
Douglas Gregor
dgregor at apple.com
Tue Aug 10 19:15:33 PDT 2010
Author: dgregor
Date: Tue Aug 10 21:15:33 2010
New Revision: 110773
URL: http://llvm.org/viewvc/llvm-project?rev=110773&view=rev
Log:
Improve our handling of user-defined conversions when computing
implicit conversion sequences. In particular, model the "standard
conversion" from a class to its own type (or a base type) directly as
a standard conversion in the normal path *without* trying to determine
if there is a valid copy constructor. This appears to match the intent
of C++ [over.best.ics]p6 and more closely matches GCC and EDG.
As part of this, model non-lvalue reference initialization via
user-defined conversion in overloading the same way we handle it in
InitializationSequence, separating the "general user-defined
conversion" and "conversion to compatible class type" cases.
The churn in the overload-call-copycon.cpp test case is because the
test case was originally wrong; it assumed that we should do more
checking for copy constructors that we actually should, which affected
overload resolution.
Fixes PR7055. Bootstrapped okay.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp
cfe/trunk/test/SemaCXX/conversion-function.cpp
cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=110773&r1=110772&r2=110773&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Aug 10 21:15:33 2010
@@ -1212,7 +1212,7 @@
"%select{|function|||function||||"
"function (the implicit copy assignment operator)}0 not viable: "
"'this' argument has type %2, but method is not marked "
- "%select{const|volatile|const or volatile|restrict|const or restrict|"
+ "%select{const|restrict|const or restrict|volatile|const or volatile|"
"volatile or restrict|const, volatile, or restrict}3">;
def note_ovl_candidate_bad_cvr : Note<"candidate "
"%select{function|function|constructor|"
@@ -1221,7 +1221,7 @@
"constructor (the implicit copy constructor)|"
"function (the implicit copy assignment operator)}0%1 not viable: "
"%ordinal4 argument (%2) would lose "
- "%select{const|volatile|const and volatile|restrict|const and restrict|"
+ "%select{const|restrict|const and restrict|volatile|const and volatile|"
"volatile and restrict|const, volatile, and restrict}3 qualifier"
"%select{||s||s|s|s}3">;
def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate "
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=110773&r1=110772&r2=110773&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Aug 10 21:15:33 2010
@@ -685,24 +685,17 @@
return ICS;
}
- if (SuppressUserConversions) {
- // C++ [over.ics.user]p4:
- // A conversion of an expression of class type to the same class
- // type is given Exact Match rank, and a conversion of an
- // expression of class type to a base class of that type is
- // given Conversion rank, in spite of the fact that a copy/move
- // constructor (i.e., a user-defined conversion function) is
- // called for those cases.
- QualType FromType = From->getType();
- if (!ToType->getAs<RecordType>() || !FromType->getAs<RecordType>() ||
- !(Context.hasSameUnqualifiedType(FromType, ToType) ||
- IsDerivedFrom(FromType, ToType))) {
- // We're not in the case above, so there is no conversion that
- // we can perform.
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- return ICS;
- }
-
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy/move
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ QualType FromType = From->getType();
+ if (ToType->getAs<RecordType>() && FromType->getAs<RecordType>() &&
+ (Context.hasSameUnqualifiedType(FromType, ToType) ||
+ IsDerivedFrom(FromType, ToType))) {
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
@@ -713,11 +706,18 @@
// exists. When we actually perform initialization, we'll find the
// appropriate constructor to copy the returned object, if needed.
ICS.Standard.CopyConstructor = 0;
-
+
// Determine whether this is considered a derived-to-base conversion.
if (!Context.hasSameUnqualifiedType(FromType, ToType))
ICS.Standard.Second = ICK_Derived_To_Base;
-
+
+ return ICS;
+ }
+
+ if (SuppressUserConversions) {
+ // We're not in the case above, so there is no conversion that
+ // we can perform.
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
return ICS;
}
@@ -2630,16 +2630,21 @@
return Ref_Related;
}
-/// \brief Look for a user-defined conversion to an lvalue reference-compatible
+/// \brief Look for a user-defined conversion to an value reference-compatible
/// with DeclType. Return true if something definite is found.
static bool
-FindConversionToLValue(Sema &S, ImplicitConversionSequence &ICS,
- QualType DeclType, SourceLocation DeclLoc,
- Expr *Init, QualType T2, bool AllowExplicit) {
+FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
+ QualType DeclType, SourceLocation DeclLoc,
+ Expr *Init, QualType T2, bool AllowRvalues,
+ bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
+ QualType ToType
+ = AllowRvalues? DeclType->getAs<ReferenceType>()->getPointeeType()
+ : DeclType;
+
OverloadCandidateSet CandidateSet(DeclLoc);
const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
@@ -2658,21 +2663,40 @@
else
Conv = cast<CXXConversionDecl>(D);
- // If the conversion function doesn't return a reference type,
- // it can't be considered for this conversion. An rvalue reference
- // is only acceptable if its referencee is a function type.
- const ReferenceType *RefType =
- Conv->getConversionType()->getAs<ReferenceType>();
- if (RefType && (RefType->isLValueReferenceType() ||
- RefType->getPointeeType()->isFunctionType()) &&
- (AllowExplicit || !Conv->isExplicit())) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
- Init, DeclType, CandidateSet);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
- DeclType, CandidateSet);
+ // If this is an explicit conversion, and we're not allowed to consider
+ // explicit conversions, skip it.
+ if (!AllowExplicit && Conv->isExplicit())
+ continue;
+
+ if (AllowRvalues) {
+ bool DerivedToBase = false;
+ bool ObjCConversion = false;
+ if (!ConvTemplate &&
+ S.CompareReferenceRelationship(DeclLoc,
+ Conv->getConversionType().getNonReferenceType().getUnqualifiedType(),
+ DeclType.getNonReferenceType().getUnqualifiedType(),
+ DerivedToBase, ObjCConversion)
+ == Sema::Ref_Incompatible)
+ continue;
+ } else {
+ // If the conversion function doesn't return a reference type,
+ // it can't be considered for this conversion. An rvalue reference
+ // is only acceptable if its referencee is a function type.
+
+ const ReferenceType *RefType =
+ Conv->getConversionType()->getAs<ReferenceType>();
+ if (!RefType ||
+ (!RefType->isLValueReferenceType() &&
+ !RefType->getPointeeType()->isFunctionType()))
+ continue;
}
+
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
+ Init, ToType, CandidateSet);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
+ ToType, CandidateSet);
}
OverloadCandidateSet::iterator Best;
@@ -2808,8 +2832,9 @@
if (!SuppressUserConversions && T2->isRecordType() &&
!S.RequireCompleteType(DeclLoc, T2, 0) &&
RefRelationship == Sema::Ref_Incompatible) {
- if (FindConversionToLValue(S, ICS, DeclType, DeclLoc,
- Init, T2, AllowExplicit))
+ if (FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
+ Init, T2, /*AllowRvalues=*/false,
+ AllowExplicit))
return ICS;
}
}
@@ -2861,28 +2886,37 @@
// that is the result of the conversion in the second case
// (or, in either case, to the appropriate base class
// subobject of the object).
- //
- // We're only checking the first case here, which is a direct
- // binding in C++0x but not in C++03.
- if (InitCategory.isRValue() && T2->isRecordType() &&
- RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
- ICS.setStandard();
- ICS.Standard.First = ICK_Identity;
- ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
- : ObjCConversion? ICK_Compatible_Conversion
- : ICK_Identity;
- ICS.Standard.Third = ICK_Identity;
- ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS.Standard.setToType(0, T2);
- ICS.Standard.setToType(1, T1);
- ICS.Standard.setToType(2, T1);
- ICS.Standard.ReferenceBinding = true;
- ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x;
- ICS.Standard.RRefBinding = isRValRef;
- ICS.Standard.CopyConstructor = 0;
- return ICS;
+ if (T2->isRecordType()) {
+ // First case: "cv1 T1" is reference-compatible with "cv2 T2". This is a
+ // direct binding in C++0x but not in C++03.
+ if (InitCategory.isRValue() &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ ICS.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
+ : ObjCConversion? ICK_Compatible_Conversion
+ : ICK_Identity;
+ ICS.Standard.Third = ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setToType(0, T2);
+ ICS.Standard.setToType(1, T1);
+ ICS.Standard.setToType(2, T1);
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x;
+ ICS.Standard.RRefBinding = isRValRef;
+ ICS.Standard.CopyConstructor = 0;
+ return ICS;
+ }
+
+ // Second case: not reference-related.
+ if (RefRelationship == Sema::Ref_Incompatible &&
+ !S.RequireCompleteType(DeclLoc, T2, 0) &&
+ FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
+ Init, T2, /*AllowRvalues=*/true,
+ AllowExplicit))
+ return ICS;
}
-
+
// -- Otherwise, a temporary of type "cv1 T1" is created and
// initialized from the initializer expression using the
// rules for a non-reference copy initialization (8.5). The
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp?rev=110773&r1=110772&r2=110773&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p9.cpp Tue Aug 10 21:15:33 2010
@@ -1,12 +1,11 @@
// RUN: %clang_cc1 -verify %s
-struct S; // expected-note {{forward declaration of 'S'}}
+struct S; // expected-note 2{{forward declaration of 'S'}}
extern S a;
extern S f(); // expected-note {{'f' declared here}}
-extern void g(S a); // expected-note {{candidate function}}
+extern void g(S a);
void h() {
- // FIXME: This diagnostic could be better.
- g(a); // expected-error {{no matching function for call to 'g'}}
+ g(a); // expected-error {{argument type 'S' is incomplete}}
f(); // expected-error {{calling 'f' with incomplete return type 'S'}}
}
Modified: cfe/trunk/test/SemaCXX/conversion-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conversion-function.cpp?rev=110773&r1=110772&r2=110773&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conversion-function.cpp (original)
+++ cfe/trunk/test/SemaCXX/conversion-function.cpp Tue Aug 10 21:15:33 2010
@@ -214,3 +214,37 @@
void test_any() {
Any any = Other(); // expected-error{{cannot pass object of non-POD type 'Other' through variadic constructor; call will abort at runtime}}
}
+
+namespace PR7055 {
+ // Make sure that we don't allow too many conversions in an
+ // auto_ptr-like template. In particular, we can't create multiple
+ // temporary objects when binding to a reference.
+ struct auto_ptr {
+ struct auto_ptr_ref { };
+
+ auto_ptr(auto_ptr&);
+ auto_ptr(auto_ptr_ref);
+ explicit auto_ptr(int *);
+
+ operator auto_ptr_ref();
+ };
+
+ struct X {
+ X(auto_ptr);
+ };
+
+ X f() {
+ X x(auto_ptr(new int));
+ return X(auto_ptr(new int));
+ }
+
+ auto_ptr foo();
+
+ X e(foo());
+
+ struct Y {
+ Y(X);
+ };
+
+ Y f2(foo());
+}
Modified: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call-copycon.cpp?rev=110773&r1=110772&r2=110773&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call-copycon.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call-copycon.cpp Tue Aug 10 21:15:33 2010
@@ -1,40 +1,44 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wnon-pod-varargs
-class X { };
+class X { }; // expected-note {{the implicit copy constructor}} \
+ // expected-note{{the implicit default constructor}}
-int& copycon(X x);
+int& copycon(X x); // expected-note{{passing argument to parameter}}
float& copycon(...);
void test_copycon(X x, X const xc, X volatile xv) {
int& i1 = copycon(x);
int& i2 = copycon(xc);
- float& f1 = copycon(xv);
+ copycon(xv); // expected-error{{no matching constructor}}
}
class A {
public:
- A(A&);
+ A(A&); // expected-note{{would lose const qualifier}} \
+ // expected-note{{no known conversion}}
};
-class B : public A { };
+class B : public A { }; // expected-note{{would lose const qualifier}} \
+// expected-note{{would lose volatile qualifier}} \
+// expected-note 2{{requires 0 arguments}}
-short& copycon2(A a);
-int& copycon2(B b);
+short& copycon2(A a); // expected-note{{passing argument to parameter}}
+int& copycon2(B b); // expected-note 2{{passing argument to parameter}}
float& copycon2(...);
void test_copycon2(A a, const A ac, B b, B const bc, B volatile bv) {
int& i1 = copycon2(b);
- float& f1 = copycon2(bc); // expected-warning {{cannot pass object of non-POD type}}
- float& f2 = copycon2(bv); // expected-warning {{cannot pass object of non-POD type}}
+ copycon2(bc); // expected-error{{no matching constructor}}
+ copycon2(bv); // expected-error{{no matching constructor}}
short& s1 = copycon2(a);
- float& f3 = copycon2(ac); // expected-warning {{cannot pass object of non-POD type}}
+ copycon2(ac); // expected-error{{no matching constructor}}
}
-int& copycon3(A a);
+int& copycon3(A a); // expected-note{{passing argument to parameter 'a' here}}
float& copycon3(...);
void test_copycon3(B b, const B bc) {
int& i1 = copycon3(b);
- float& f1 = copycon3(bc); // expected-warning {{cannot pass object of non-POD type}}
+ copycon3(bc); // expected-error{{no matching constructor}}
}
class C : public B { };
More information about the cfe-commits
mailing list