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
This commit is contained in:
Douglas Gregor 2009-12-19 03:01:41 +00:00
Родитель 29f1a6070a
Коммит 7abfbdbc97
16 изменённых файлов: 106 добавлений и 118 удалений

Просмотреть файл

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

Просмотреть файл

@ -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());
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;
// -- 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;
}
// -- 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;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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> { };

Просмотреть файл

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