зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
29f1a6070a
Коммит
7abfbdbc97
|
@ -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}}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче