forked from OSchip/llvm-project
Fix nothrow trait with multiple default constructors
Check all default ctors, not just the first one we see. This brings __has_nothrow_constructor() in line with the other unary type traits. A C++ class can have multiple default constructors but clang was only checking the first one written, presumably due to ambiguity in the GNU specification. MSVC has the same bug, while g++ has the correct implementation which we now match. llvm-svn: 199618
This commit is contained in:
parent
f600441a04
commit
b4bca41491
|
@ -3516,7 +3516,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case UTT_HasNothrowConstructor:
|
case UTT_HasNothrowConstructor:
|
||||||
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
|
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
|
||||||
// If __has_trivial_constructor (type) is true then the trait is
|
// If __has_trivial_constructor (type) is true then the trait is
|
||||||
// true, else if type is a cv class or union type (or array
|
// true, else if type is a cv class or union type (or array
|
||||||
// thereof) with a default constructor that is known not to
|
// thereof) with a default constructor that is known not to
|
||||||
|
@ -3528,6 +3528,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
|
||||||
!RD->hasNonTrivialDefaultConstructor())
|
!RD->hasNonTrivialDefaultConstructor())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
bool FoundConstructor = false;
|
||||||
DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
|
DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
|
||||||
for (DeclContext::lookup_const_iterator Con = R.begin(),
|
for (DeclContext::lookup_const_iterator Con = R.begin(),
|
||||||
ConEnd = R.end(); Con != ConEnd; ++Con) {
|
ConEnd = R.end(); Con != ConEnd; ++Con) {
|
||||||
|
@ -3536,16 +3537,19 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
|
||||||
continue;
|
continue;
|
||||||
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
||||||
if (Constructor->isDefaultConstructor()) {
|
if (Constructor->isDefaultConstructor()) {
|
||||||
|
FoundConstructor = true;
|
||||||
const FunctionProtoType *CPT
|
const FunctionProtoType *CPT
|
||||||
= Constructor->getType()->getAs<FunctionProtoType>();
|
= Constructor->getType()->getAs<FunctionProtoType>();
|
||||||
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
|
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
|
||||||
if (!CPT)
|
if (!CPT)
|
||||||
return false;
|
return false;
|
||||||
// TODO: check whether evaluating default arguments can throw.
|
// FIXME: check whether evaluating default arguments can throw.
|
||||||
// For now, we'll be conservative and assume that they can throw.
|
// For now, we'll be conservative and assume that they can throw.
|
||||||
return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
|
if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 0)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return FoundConstructor;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case UTT_HasVirtualDestructor:
|
case UTT_HasVirtualDestructor:
|
||||||
|
|
|
@ -112,6 +112,14 @@ struct HasNoThrowConstructor { HasNoThrowConstructor() throw(); };
|
||||||
struct HasNoThrowConstructorWithArgs {
|
struct HasNoThrowConstructorWithArgs {
|
||||||
HasNoThrowConstructorWithArgs(HasCons i = HasCons(0)) throw();
|
HasNoThrowConstructorWithArgs(HasCons i = HasCons(0)) throw();
|
||||||
};
|
};
|
||||||
|
struct HasMultipleDefaultConstructor1 {
|
||||||
|
HasMultipleDefaultConstructor1() throw();
|
||||||
|
HasMultipleDefaultConstructor1(int i = 0);
|
||||||
|
};
|
||||||
|
struct HasMultipleDefaultConstructor2 {
|
||||||
|
HasMultipleDefaultConstructor2(int i = 0);
|
||||||
|
HasMultipleDefaultConstructor2() throw();
|
||||||
|
};
|
||||||
|
|
||||||
struct HasNoThrowCopy { HasNoThrowCopy(const HasNoThrowCopy&) throw(); };
|
struct HasNoThrowCopy { HasNoThrowCopy(const HasNoThrowCopy&) throw(); };
|
||||||
struct HasMultipleCopy {
|
struct HasMultipleCopy {
|
||||||
|
@ -1562,6 +1570,9 @@ void has_nothrow_constructor() {
|
||||||
{ int arr[F(__has_nothrow_constructor(void))]; }
|
{ int arr[F(__has_nothrow_constructor(void))]; }
|
||||||
{ int arr[F(__has_nothrow_constructor(cvoid))]; }
|
{ int arr[F(__has_nothrow_constructor(cvoid))]; }
|
||||||
{ int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
|
{ int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
|
||||||
|
|
||||||
|
{ int arr[F(__has_nothrow_constructor(HasMultipleDefaultConstructor1))]; }
|
||||||
|
{ int arr[F(__has_nothrow_constructor(HasMultipleDefaultConstructor2))]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void has_virtual_destructor() {
|
void has_virtual_destructor() {
|
||||||
|
|
Loading…
Reference in New Issue