diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-12-19 03:01:41 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-12-19 03:01:41 +0000 |
commit | 7abfbdbc97ad8e7f340789f751df1e32b10118b4 (patch) | |
tree | c98c3dd47e10bceea032ec5fb2b44306f109dacd | |
parent | 29f1a6070ac35fcbea9241c843df7f3f7c5c3228 (diff) |
Switch more of Sema::CheckInitializerTypes over to
InitializationSequence. Specially, switch initialization of a C++
class type (either copy- or direct-initialization).
Also, make sure that we create an elidable copy-construction when
performing copy initialization of a C++ class variable. Fixes PR5826.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91750 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 12 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 123 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 6 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp | 4 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp | 4 | ||||
-rw-r--r-- | test/CXX/temp/temp.param/p3.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenCXX/constructor-init.cpp | 23 | ||||
-rw-r--r-- | test/SemaCXX/condition.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/conversion-function.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/converting-constructor.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/copy-initialization.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/dcl_init_aggr.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/default1.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/nested-name-spec.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/default-expr-arguments.cpp | 8 | ||||
-rw-r--r-- | test/SemaTemplate/fun-template-def.cpp | 4 |
16 files changed, 106 insertions, 118 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b9c1897a1e..b2ff5ee105 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -578,14 +578,14 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">, InGroup<DiagGroup<"uninitialized">>; def err_temp_copy_no_viable : Error< - "no viable copy constructor %select{throwing|returning}0 object of type %1">; + "no viable copy constructor %select{copying variable|copying parameter|" + "returning object|throwing object}0 of type %1">; def err_temp_copy_ambiguous : Error< - "ambiguous copy constructor call when %select{throwing|returning}0 object of " - "type %1">; + "ambiguous copy constructor call when %select{copying variable|copying " + "parameter|returning object|throwing object}0 of type %1">; def err_temp_copy_deleted : Error< - "%select{throwing|returning}0 object of type %1 invokes deleted copy " - "constructor">; - + "%select{copying variable|copying parameter|returning object|throwing " + "object}0 of type %1 invokes deleted copy constructor">; // C++0x decltype def err_cannot_determine_declared_type_of_overloaded_function : Error< diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 60de672c0a..6f11a87d11 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -222,79 +222,15 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, // -- If the destination type is a (possibly cv-qualified) class // type: if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { - QualType DeclTypeC = Context.getCanonicalType(DeclType); - QualType InitTypeC = Context.getCanonicalType(Init->getType()); - - // -- If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. - if ((DeclTypeC.getLocalUnqualifiedType() - == InitTypeC.getLocalUnqualifiedType()) || - IsDerivedFrom(InitTypeC, DeclTypeC)) { - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl()); - - // No need to make a CXXConstructExpr if both the ctor and dtor are - // trivial. - if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor()) - return false; - - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - // FIXME: Poor location information - InitializationKind InitKind - = InitializationKind::CreateCopy(Init->getLocStart(), - SourceLocation()); - if (DirectInit) - InitKind = InitializationKind::CreateDirect(Init->getLocStart(), - SourceLocation(), - SourceLocation()); - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(DeclType, - MultiExprArg(*this, - (void **)&Init, 1), - InitLoc, Init->getSourceRange(), - InitEntity, InitKind, - ConstructorArgs); - if (!Constructor) - return true; - - OwningExprResult InitResult = - BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), - DeclType, Constructor, - move_arg(ConstructorArgs)); - if (InitResult.isInvalid()) - return true; - - Init = InitResult.takeAs<Expr>(); - return false; - } + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + OwningExprResult CurInit = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1), + &DeclType); + if (CurInit.isInvalid()) + return true; - // -- Otherwise (i.e., for the remaining copy-initialization - // cases), user-defined conversion sequences that can - // convert from the source type to the destination type or - // (when a conversion function is used) to a derived class - // thereof are enumerated as described in 13.3.1.4, and the - // best one is chosen through overload resolution - // (13.3). If the conversion cannot be done or is - // ambiguous, the initialization is ill-formed. The - // function selected is called with the initializer - // expression as its argument; if the function is a - // constructor, the call initializes a temporary of the - // destination type. - // FIXME: We're pretending to do copy elision here; return to this when we - // have ASTs for such things. - if (!PerformImplicitConversion(Init, DeclType, Sema::AA_Initializing)) - return false; - - if (InitEntity) - return Diag(InitLoc, diag::err_cannot_initialize_decl) - << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) - << Init->getType() << Init->getSourceRange(); - return Diag(InitLoc, diag::err_cannot_initialize_decl_noname) - << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) - << Init->getType() << Init->getSourceRange(); + Init = CurInit.takeAs<Expr>(); + return false; } // C99 6.7.8p16. @@ -2014,6 +1950,26 @@ DeclarationName InitializedEntity::getName() const { return DeclarationName(); } +DeclaratorDecl *InitializedEntity::getDecl() const { + switch (getKind()) { + case EK_Variable: + case EK_Parameter: + case EK_Member: + return VariableOrMember; + + case EK_Result: + case EK_Exception: + case EK_New: + case EK_Temporary: + case EK_Base: + case EK_ArrayOrVectorElement: + return 0; + } + + // Silence GCC warning + return 0; +} + //===----------------------------------------------------------------------===// // Initialization sequence //===----------------------------------------------------------------------===// @@ -3051,25 +3007,32 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity, /// thrown), make the copy. static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, const InitializedEntity &Entity, + const InitializationKind &Kind, Sema::OwningExprResult CurInit) { SourceLocation Loc; - bool isReturn = false; switch (Entity.getKind()) { case InitializedEntity::EK_Result: if (Entity.getType().getType()->isReferenceType()) return move(CurInit); - isReturn = true; Loc = Entity.getReturnLoc(); break; case InitializedEntity::EK_Exception: - isReturn = false; Loc = Entity.getThrowLoc(); break; case InitializedEntity::EK_Variable: + if (Entity.getType().getType()->isReferenceType() || + Kind.getKind() != InitializationKind::IK_Copy) + return move(CurInit); + Loc = Entity.getDecl()->getLocation(); + break; + case InitializedEntity::EK_Parameter: + // FIXME: Do we need this initialization for a parameter? + return move(CurInit); + case InitializedEntity::EK_New: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_Base: @@ -3110,21 +3073,21 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, case OR_No_Viable_Function: S.Diag(Loc, diag::err_temp_copy_no_viable) - << isReturn << CurInitExpr->getType() + << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); S.PrintOverloadCandidates(CandidateSet, false); return S.ExprError(); case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) - << isReturn << CurInitExpr->getType() + << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); S.PrintOverloadCandidates(CandidateSet, true); return S.ExprError(); case OR_Deleted: S.Diag(Loc, diag::err_temp_copy_deleted) - << isReturn << CurInitExpr->getType() + << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) << Best->Function->isDeleted(); @@ -3364,7 +3327,7 @@ InitializationSequence::Perform(Sema &S, false)); if (!IsCopy) - CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit)); + CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit)); break; } @@ -3425,7 +3388,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); if (!Elidable) - CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit)); + CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit)); break; } diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index c42badd3f8..1987ad0734 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -195,7 +195,11 @@ public: /// \brief Retrieve the name of the entity being initialized. DeclarationName getName() const; - + + /// \brief Retrieve the variable, parameter, or field being + /// initialized. + DeclaratorDecl *getDecl() const; + /// \brief Determine the location of the 'return' keyword when initializing /// the result of a function call. SourceLocation getReturnLoc() const { diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp index d02e5f3e57..aa53ebc580 100644 --- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp +++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp @@ -8,13 +8,13 @@ struct X { }; template<typename T> - T X<T>::value = 17; // expected-error{{initialize}} + T X<T>::value = 17; // expected-error{{no viable conversion}} struct InitOkay { InitOkay(int) { } }; -struct CannotInit { }; +struct CannotInit { }; // expected-note{{candidate function}} int &returnInt() { return X<int>::value; } float &returnFloat() { return X<float>::value; } diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp index 58479cda26..3cefeb821e 100644 --- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp +++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp @@ -6,13 +6,13 @@ struct X0 { }; template<typename T> -T X0<T>::value = 0; // expected-error{{initialize}} +T X0<T>::value = 0; // expected-error{{no viable conversion}} struct X1 { X1(int); }; -struct X2 { }; +struct X2 { }; // expected-note{{candidate function}} int& get_int() { return X0<int>::value; } X1& get_X1() { return X0<X1>::value; } diff --git a/test/CXX/temp/temp.param/p3.cpp b/test/CXX/temp/temp.param/p3.cpp index 7576aae478..67d648ea97 100644 --- a/test/CXX/temp/temp.param/p3.cpp +++ b/test/CXX/temp/temp.param/p3.cpp @@ -15,7 +15,7 @@ template<template<class T> class Y> struct X1 { // could be interpreted as either a non-type template-parameter or a // type-parameter (because its identifier is the name of an already // existing class) is taken as a type-parameter. For example, -class T { /* ... */ }; +class T { /* ... */ }; // expected-note{{candidate function}} int i; template<class T, T i> struct X2 { @@ -23,6 +23,6 @@ template<class T, T i> struct X2 { { T t1 = i; //template-parameters T and i ::T t2 = ::i; // global namespace members T and i \ - // expected-error{{cannot initialize}} + // expected-error{{no viable conversion}} } }; diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp index ae6014fc66..a0a35fa16f 100644 --- a/test/CodeGenCXX/constructor-init.cpp +++ b/test/CodeGenCXX/constructor-init.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o %t +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s extern "C" int printf(...); @@ -59,3 +59,24 @@ int main() { n1.PR(); } +// PR5826 +template <class T> struct A { + A() {} + A(int) {} + A(const A&) {} + ~A() {} + operator int() {return 0;} +}; + +// CHECK: define void @_Z1fv() +void f() { + // CHECK: call void @_ZN1AIsEC1Ei + A<short> a4 = 97; + + // CHECK-NEXT: store i32 17 + int i = 17; + + // CHECK-NEXT: call void @_ZN1AIsED1Ev + // CHECK-NOT: call void @_ZN1AIsED1Ev + // CHECK: ret void +} diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp index 7a51f7e096..aede25e3f7 100644 --- a/test/SemaCXX/condition.cpp +++ b/test/SemaCXX/condition.cpp @@ -16,8 +16,8 @@ void test() { for (;s;) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}} - while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} - while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}} + while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} expected-note{{candidate function}} + while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}} expected-note{{candidate function}} switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} if (int x=0) { // expected-note 2 {{previous definition is here}} diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp index fca5a4a72a..db322f4a3d 100644 --- a/test/SemaCXX/conversion-function.cpp +++ b/test/SemaCXX/conversion-function.cpp @@ -56,14 +56,14 @@ public: // This used to crash Clang. struct Flip; -struct Flop { +struct Flop { // expected-note{{candidate function}} Flop(); - Flop(const Flip&); + Flop(const Flip&); // expected-note{{candidate function}} }; struct Flip { - operator Flop() const; + operator Flop() const; // expected-note{{candidate function}} }; -Flop flop = Flip(); // expected-error {{cannot initialize 'flop' with an rvalue of type 'struct Flip'}} +Flop flop = Flip(); // expected-error {{conversion from 'struct Flip' to 'struct Flop' is ambiguous}} // This tests that we don't add the second conversion declaration to the list of user conversions struct C { diff --git a/test/SemaCXX/converting-constructor.cpp b/test/SemaCXX/converting-constructor.cpp index e0e614ebe5..e78798b82c 100644 --- a/test/SemaCXX/converting-constructor.cpp +++ b/test/SemaCXX/converting-constructor.cpp @@ -27,7 +27,7 @@ public: FromShort(short s); }; -class FromShortExplicitly { +class FromShortExplicitly { // expected-note{{candidate function}} public: explicit FromShortExplicitly(short s); }; @@ -36,7 +36,7 @@ void explicit_constructor(short s) { FromShort fs1(s); FromShort fs2 = s; FromShortExplicitly fse1(s); - FromShortExplicitly fse2 = s; // expected-error{{error: cannot initialize 'fse2' with an lvalue of type 'short'}} + FromShortExplicitly fse2 = s; // expected-error{{no viable conversion}} } // PR5519 diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp index 8df0c6340f..ad149232a4 100644 --- a/test/SemaCXX/copy-initialization.cpp +++ b/test/SemaCXX/copy-initialization.cpp @@ -2,17 +2,17 @@ class X { public: explicit X(const X&); - X(int*); // expected-note{{candidate function}} + X(int*); // expected-note 2{{candidate function}} explicit X(float*); }; class Y : public X { }; void f(Y y, int *ip, float *fp) { - X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidate is:}} + X x1 = y; // expected-error{{no matching constructor for initialization of 'class X'}} X x2 = 0; X x3 = ip; - X x4 = fp; // expected-error{{cannot initialize 'x4' with an lvalue of type 'float *'}} + X x4 = fp; // expected-error{{no viable conversion}} } struct foo { diff --git a/test/SemaCXX/dcl_init_aggr.cpp b/test/SemaCXX/dcl_init_aggr.cpp index f7dc8f11c7..98aa7218f5 100644 --- a/test/SemaCXX/dcl_init_aggr.cpp +++ b/test/SemaCXX/dcl_init_aggr.cpp @@ -115,9 +115,9 @@ B2 b2_2 = { 4, d2, 0 }; B2 b2_3 = { c2, a2, a2 }; // C++ [dcl.init.aggr]p15: -union u { int a; char* b; }; +union u { int a; char* b; }; // expected-note{{candidate function}} u u1 = { 1 }; u u2 = u1; -u u3 = 1; // expected-error{{cannot initialize 'u3' with an rvalue of type 'int'}} +u u3 = 1; // expected-error{{no viable conversion}} u u4 = { 0, "asdf" }; // expected-error{{excess elements in union initializer}} u u5 = { "asdf" }; // expected-error{{incompatible type initializing 'char const [5]', expected 'int'}} diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp index 497a6b10ac..eab54f47b9 100644 --- a/test/SemaCXX/default1.cpp +++ b/test/SemaCXX/default1.cpp @@ -22,10 +22,10 @@ struct X { void j(X x = 17); -struct Y { +struct Y { // expected-note 2{{candidate}} explicit Y(int); }; -void k(Y y = 17); // expected-error{{cannot initialize 'y' with an rvalue of type 'int'}} +void k(Y y = 17); // expected-error{{no viable conversion}} -void kk(Y = 17); // expected-error{{cannot initialize a value of type 'struct Y' with an rvalue of type 'int'}} +void kk(Y = 17); // expected-error{{no viable conversion}} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index dc8eda5994..454af5ef19 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -178,7 +178,7 @@ bool (foo_S::value); namespace somens { - struct a { }; + struct a { }; // expected-note{{candidate function}} } template <typename T> @@ -189,7 +189,7 @@ class foo { // PR4452 / PR4451 foo<somens:a> a2; // expected-error {{unexpected ':' in nested name specifier}} -somens::a a3 = a2; // expected-error {{cannot initialize 'a3' with an lvalue of type 'foo<somens::a>'}} +somens::a a3 = a2; // expected-error {{no viable conversion}} // typedefs and using declarations. namespace test1 { diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp index 4c2f5465dc..df3cc96ba2 100644 --- a/test/SemaTemplate/default-expr-arguments.cpp +++ b/test/SemaTemplate/default-expr-arguments.cpp @@ -6,9 +6,9 @@ class C { C(int a0 = 0); }; template<> C<char>::C(int a0); -struct S { }; +struct S { }; // expected-note 3 {{candidate function}} -template<typename T> void f1(T a, T b = 10) { } // expected-error{{cannot initialize 'b' with an rvalue of type 'int'}} +template<typename T> void f1(T a, T b = 10) { } // expected-error{{no viable conversion}} template<typename T> void f2(T a, T b = T()) { } @@ -26,8 +26,8 @@ void g() { } template<typename T> struct F { - F(T t = 10); // expected-error{{cannot initialize 't' with an rvalue of type 'int'}} - void f(T t = 10); // expected-error{{cannot initialize 't' with an rvalue of type 'int'}} + F(T t = 10); // expected-error{{no viable conversion}} + void f(T t = 10); // expected-error{{no viable conversion}} }; struct FD : F<int> { }; diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp index 867b1c643e..cc28553ebc 100644 --- a/test/SemaTemplate/fun-template-def.cpp +++ b/test/SemaTemplate/fun-template-def.cpp @@ -8,7 +8,7 @@ // Fake typeid, lacking a typeinfo header. namespace std { class type_info {}; } -struct dummy {}; +struct dummy {}; // expected-note{{candidate function}} template<typename T> int f0(T x) { @@ -40,7 +40,7 @@ T f1(T t1, U u1, int i1) delete t1; dummy d1 = sizeof(t1); // FIXME: delayed checking okay? - dummy d2 = offsetof(T, foo); // expected-error {{cannot initialize 'd2'}} + dummy d2 = offsetof(T, foo); // expected-error {{no viable conversion}} dummy d3 = __alignof(u1); // FIXME: delayed checking okay? i1 = typeid(t1); // expected-error {{incompatible type assigning}} |