forked from OSchip/llvm-project
PR 12586: Fix assert while running libc++ testsuite: deal with exception
specifications on member function templates of class templates and other such nested beasties. Store the function template from which we are to instantiate an exception specification rather than trying to deduce it. Plus some additional test cases. llvm-svn: 155076
This commit is contained in:
parent
925a6d08c5
commit
d372942d77
|
@ -2701,7 +2701,8 @@ public:
|
||||||
ExtProtoInfo() :
|
ExtProtoInfo() :
|
||||||
Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None),
|
ExceptionSpecType(EST_None), RefQualifier(RQ_None),
|
||||||
NumExceptions(0), Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),
|
NumExceptions(0), Exceptions(0), NoexceptExpr(0),
|
||||||
|
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
|
||||||
ConsumedArguments(0) {}
|
ConsumedArguments(0) {}
|
||||||
|
|
||||||
FunctionType::ExtInfo ExtInfo;
|
FunctionType::ExtInfo ExtInfo;
|
||||||
|
@ -2714,6 +2715,7 @@ public:
|
||||||
const QualType *Exceptions;
|
const QualType *Exceptions;
|
||||||
Expr *NoexceptExpr;
|
Expr *NoexceptExpr;
|
||||||
FunctionDecl *ExceptionSpecDecl;
|
FunctionDecl *ExceptionSpecDecl;
|
||||||
|
FunctionDecl *ExceptionSpecTemplate;
|
||||||
const bool *ConsumedArguments;
|
const bool *ConsumedArguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2759,9 +2761,10 @@ private:
|
||||||
// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
|
// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
|
||||||
// to the expression in the noexcept() specifier.
|
// to the expression in the noexcept() specifier.
|
||||||
|
|
||||||
// ExceptionSpecDecl - Instead of Exceptions, there may be a single
|
// ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may
|
||||||
// FunctionDecl* pointing to the function which should be used to resolve
|
// be a pair of FunctionDecl* pointing to the function which should be used to
|
||||||
// this function type's exception specification.
|
// instantiate this function type's exception specification, and the function
|
||||||
|
// from which it should be instantiated.
|
||||||
|
|
||||||
// ConsumedArgs - A variable size array, following Exceptions
|
// ConsumedArgs - A variable size array, following Exceptions
|
||||||
// and of length NumArgs, holding flags indicating which arguments
|
// and of length NumArgs, holding flags indicating which arguments
|
||||||
|
@ -2804,6 +2807,7 @@ public:
|
||||||
EPI.NoexceptExpr = getNoexceptExpr();
|
EPI.NoexceptExpr = getNoexceptExpr();
|
||||||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||||
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
||||||
|
EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();
|
||||||
}
|
}
|
||||||
if (hasAnyConsumedArgs())
|
if (hasAnyConsumedArgs())
|
||||||
EPI.ConsumedArguments = getConsumedArgsBuffer();
|
EPI.ConsumedArguments = getConsumedArgsBuffer();
|
||||||
|
@ -2847,10 +2851,22 @@ public:
|
||||||
// NoexceptExpr sits where the arguments end.
|
// NoexceptExpr sits where the arguments end.
|
||||||
return *reinterpret_cast<Expr *const *>(arg_type_end());
|
return *reinterpret_cast<Expr *const *>(arg_type_end());
|
||||||
}
|
}
|
||||||
|
/// \brief If this function type has an uninstantiated exception
|
||||||
|
/// specification, this is the function whose exception specification
|
||||||
|
/// is represented by this type.
|
||||||
FunctionDecl *getExceptionSpecDecl() const {
|
FunctionDecl *getExceptionSpecDecl() const {
|
||||||
if (getExceptionSpecType() != EST_Uninstantiated)
|
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||||
return 0;
|
return 0;
|
||||||
return *reinterpret_cast<FunctionDecl * const *>(arg_type_end());
|
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0];
|
||||||
|
}
|
||||||
|
/// \brief If this function type has an uninstantiated exception
|
||||||
|
/// specification, this is the function whose exception specification
|
||||||
|
/// should be instantiated to find the exception specification for
|
||||||
|
/// this type.
|
||||||
|
FunctionDecl *getExceptionSpecTemplate() const {
|
||||||
|
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||||
|
return 0;
|
||||||
|
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1];
|
||||||
}
|
}
|
||||||
bool isNothrow(ASTContext &Ctx) const {
|
bool isNothrow(ASTContext &Ctx) const {
|
||||||
ExceptionSpecificationType EST = getExceptionSpecType();
|
ExceptionSpecificationType EST = getExceptionSpecType();
|
||||||
|
|
|
@ -2195,7 +2195,7 @@ ASTContext::getFunctionType(QualType ResultTy,
|
||||||
else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
|
else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
|
||||||
Size += sizeof(Expr*);
|
Size += sizeof(Expr*);
|
||||||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||||
Size += sizeof(FunctionDecl*);
|
Size += 2 * sizeof(FunctionDecl*);
|
||||||
}
|
}
|
||||||
if (EPI.ConsumedArguments)
|
if (EPI.ConsumedArguments)
|
||||||
Size += NumArgs * sizeof(bool);
|
Size += NumArgs * sizeof(bool);
|
||||||
|
|
|
@ -1550,7 +1550,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
|
||||||
// Store the function decl from which we will resolve our
|
// Store the function decl from which we will resolve our
|
||||||
// exception specification.
|
// exception specification.
|
||||||
FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
|
FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
|
||||||
*slot = epi.ExceptionSpecDecl;
|
slot[0] = epi.ExceptionSpecDecl;
|
||||||
|
slot[1] = epi.ExceptionSpecTemplate;
|
||||||
// This exception specification doesn't make the type dependent, because
|
// This exception specification doesn't make the type dependent, because
|
||||||
// it's not instantiated as part of instantiating the type.
|
// it's not instantiated as part of instantiating the type.
|
||||||
}
|
}
|
||||||
|
|
|
@ -9776,9 +9776,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
|
||||||
|
|
||||||
// Instantiate the exception specification for any function which is
|
// Instantiate the exception specification for any function which is
|
||||||
// used: CodeGen will need it.
|
// used: CodeGen will need it.
|
||||||
if (Func->getTemplateInstantiationPattern() &&
|
const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
|
||||||
Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
|
if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated)
|
||||||
== EST_Uninstantiated)
|
|
||||||
InstantiateExceptionSpec(Loc, Func);
|
InstantiateExceptionSpec(Loc, Func);
|
||||||
|
|
||||||
// Implicit instantiation of function templates and member functions of
|
// Implicit instantiation of function templates and member functions of
|
||||||
|
|
|
@ -2251,6 +2251,8 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
|
||||||
static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
|
static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
|
||||||
const FunctionProtoType *Proto,
|
const FunctionProtoType *Proto,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||||
|
assert(Proto->getExceptionSpecType() != EST_Uninstantiated);
|
||||||
|
|
||||||
// C++11 [expr.prim.general]p3:
|
// C++11 [expr.prim.general]p3:
|
||||||
// If a declaration declares a member function or member function
|
// If a declaration declares a member function or member function
|
||||||
// template of a class X, the expression this is a prvalue of type
|
// template of a class X, the expression this is a prvalue of type
|
||||||
|
@ -2377,20 +2379,8 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
|
||||||
|
|
||||||
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||||
FunctionDecl *Decl) {
|
FunctionDecl *Decl) {
|
||||||
// Find the template declaration which contains the exception specification.
|
const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>();
|
||||||
// Per [except.spec]p4, prefer the exception spec on the primary template
|
if (Proto->getExceptionSpecType() != EST_Uninstantiated)
|
||||||
// if this is an explicit instantiation.
|
|
||||||
FunctionDecl *Tmpl = 0;
|
|
||||||
if (Decl->getPrimaryTemplate())
|
|
||||||
Tmpl = Decl->getPrimaryTemplate()->getTemplatedDecl();
|
|
||||||
else if (FunctionDecl *MemTmpl = Decl->getInstantiatedFromMemberFunction())
|
|
||||||
Tmpl = MemTmpl;
|
|
||||||
else
|
|
||||||
Tmpl = Decl->getTemplateInstantiationPattern();
|
|
||||||
assert(Tmpl && "can't instantiate non-template");
|
|
||||||
|
|
||||||
if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
|
|
||||||
!= EST_Uninstantiated)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
|
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
|
||||||
|
@ -2406,10 +2396,12 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||||
MultiLevelTemplateArgumentList TemplateArgs =
|
MultiLevelTemplateArgumentList TemplateArgs =
|
||||||
getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
|
getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
|
||||||
|
|
||||||
addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope, TemplateArgs);
|
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
|
||||||
|
addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs);
|
||||||
|
|
||||||
const FunctionProtoType *Proto = Tmpl->getType()->castAs<FunctionProtoType>();
|
::InstantiateExceptionSpec(*this, Decl,
|
||||||
::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);
|
Template->getType()->castAs<FunctionProtoType>(),
|
||||||
|
TemplateArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Initializes the common fields of an instantiation function
|
/// \brief Initializes the common fields of an instantiation function
|
||||||
|
@ -2457,6 +2449,10 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
|
||||||
EPI.ExceptionSpecType != EST_None &&
|
EPI.ExceptionSpecType != EST_None &&
|
||||||
EPI.ExceptionSpecType != EST_DynamicNone &&
|
EPI.ExceptionSpecType != EST_DynamicNone &&
|
||||||
EPI.ExceptionSpecType != EST_BasicNoexcept) {
|
EPI.ExceptionSpecType != EST_BasicNoexcept) {
|
||||||
|
FunctionDecl *ExceptionSpecTemplate = Tmpl;
|
||||||
|
if (EPI.ExceptionSpecType == EST_Uninstantiated)
|
||||||
|
ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
|
||||||
|
|
||||||
// Mark the function has having an uninstantiated exception specification.
|
// Mark the function has having an uninstantiated exception specification.
|
||||||
const FunctionProtoType *NewProto
|
const FunctionProtoType *NewProto
|
||||||
= New->getType()->getAs<FunctionProtoType>();
|
= New->getType()->getAs<FunctionProtoType>();
|
||||||
|
@ -2464,6 +2460,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
|
||||||
EPI = NewProto->getExtProtoInfo();
|
EPI = NewProto->getExtProtoInfo();
|
||||||
EPI.ExceptionSpecType = EST_Uninstantiated;
|
EPI.ExceptionSpecType = EST_Uninstantiated;
|
||||||
EPI.ExceptionSpecDecl = New;
|
EPI.ExceptionSpecDecl = New;
|
||||||
|
EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
|
||||||
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
|
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
|
||||||
NewProto->arg_type_begin(),
|
NewProto->arg_type_begin(),
|
||||||
NewProto->getNumArgs(),
|
NewProto->getNumArgs(),
|
||||||
|
|
|
@ -3,9 +3,11 @@
|
||||||
void h();
|
void h();
|
||||||
|
|
||||||
template<typename T> void f() noexcept(sizeof(T) == 4) { h(); }
|
template<typename T> void f() noexcept(sizeof(T) == 4) { h(); }
|
||||||
|
template<typename T> void g() noexcept(sizeof(T) == 4);
|
||||||
|
|
||||||
template<typename T> struct S {
|
template<typename T> struct S {
|
||||||
static void f() noexcept(sizeof(T) == 4) { h(); }
|
static void f() noexcept(sizeof(T) == 4) { h(); }
|
||||||
|
static void g() noexcept(sizeof(T) == 4);
|
||||||
};
|
};
|
||||||
|
|
||||||
// CHECK: define {{.*}} @_Z1fIsEvv() {
|
// CHECK: define {{.*}} @_Z1fIsEvv() {
|
||||||
|
@ -30,7 +32,7 @@ template void S<char16_t>::f();
|
||||||
// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind
|
// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind
|
||||||
template void S<char16_t[2]>::f();
|
template void S<char16_t[2]>::f();
|
||||||
|
|
||||||
void g() {
|
void h() {
|
||||||
// CHECK: define {{.*}} @_Z1fIiEvv() nounwind {
|
// CHECK: define {{.*}} @_Z1fIiEvv() nounwind {
|
||||||
f<int>();
|
f<int>();
|
||||||
// CHECK: define {{.*}} @_Z1fIA2_iEvv() {
|
// CHECK: define {{.*}} @_Z1fIA2_iEvv() {
|
||||||
|
@ -64,3 +66,55 @@ void g() {
|
||||||
// CHECK-NOT: nounwind
|
// CHECK-NOT: nounwind
|
||||||
(void)&S<char>::f;
|
(void)&S<char>::f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: define {{.*}} @_Z1iv
|
||||||
|
void i() {
|
||||||
|
// CHECK: declare {{.*}} @_Z1gIiEvv() nounwind
|
||||||
|
g<int>();
|
||||||
|
// CHECK: declare {{.*}} @_Z1gIA2_iEvv()
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
g<int[2]>();
|
||||||
|
|
||||||
|
// CHECK: declare {{.*}} @_ZN1SIiE1gEv() nounwind
|
||||||
|
S<int>::g();
|
||||||
|
// CHECK: declare {{.*}} @_ZN1SIA2_iE1gEv()
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
S<int[2]>::g();
|
||||||
|
|
||||||
|
// CHECK: declare {{.*}} @_Z1gIfEvv() nounwind
|
||||||
|
void (*g1)() = &g<float>;
|
||||||
|
// CHECK: declare {{.*}} @_Z1gIdEvv()
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
void (*g2)() = &g<double>;
|
||||||
|
|
||||||
|
// CHECK: declare {{.*}} @_ZN1SIfE1gEv() nounwind
|
||||||
|
void (*g3)() = &S<float>::g;
|
||||||
|
// CHECK: declare {{.*}} @_ZN1SIdE1gEv()
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
void (*g4)() = &S<double>::g;
|
||||||
|
|
||||||
|
// CHECK: declare {{.*}} @_Z1gIA4_cEvv() nounwind
|
||||||
|
(void)&g<char[4]>;
|
||||||
|
// CHECK: declare {{.*}} @_Z1gIcEvv()
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
(void)&g<char>;
|
||||||
|
|
||||||
|
// CHECK: declare {{.*}} @_ZN1SIA4_cE1gEv() nounwind
|
||||||
|
(void)&S<char[4]>::g;
|
||||||
|
// CHECK: declare {{.*}} @_ZN1SIcE1gEv()
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
(void)&S<char>::g;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> struct Nested {
|
||||||
|
template<bool b, typename U> void f() noexcept(sizeof(T) == sizeof(U));
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK: define {{.*}} @_Z1jv
|
||||||
|
void j() {
|
||||||
|
// CHECK: declare {{.*}} @_ZN6NestedIiE1fILb1EcEEvv(
|
||||||
|
// CHECK-NOT: nounwind
|
||||||
|
Nested<int>().f<true, char>();
|
||||||
|
// CHECK: declare {{.*}} @_ZN6NestedIlE1fILb0ElEEvv({{.*}}) nounwind
|
||||||
|
Nested<long>().f<false, long>();
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 -fcxx-exceptions -fexceptions %s
|
||||||
|
|
||||||
// DR1330: an exception specification for a function template is only
|
// DR1330: an exception specification for a function template is only
|
||||||
// instantiated when it is needed.
|
// instantiated when it is needed.
|
||||||
|
@ -31,7 +31,7 @@ decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed
|
||||||
decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
|
decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
|
||||||
|
|
||||||
template<> struct S<10> {};
|
template<> struct S<10> {};
|
||||||
void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}}
|
void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}} expected-error {{not superset}}
|
||||||
|
|
||||||
|
|
||||||
template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
|
template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
|
||||||
|
@ -118,3 +118,16 @@ namespace pr9485 {
|
||||||
f2(0); // expected-error {{ambiguous}}
|
f2(0); // expected-error {{ambiguous}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Exc1 { char c[4]; };
|
||||||
|
struct Exc2 { double x, y, z; };
|
||||||
|
struct Base {
|
||||||
|
virtual void f() noexcept; // expected-note {{overridden}}
|
||||||
|
};
|
||||||
|
template<typename T> struct Derived : Base {
|
||||||
|
void f() noexcept (sizeof(T) == 4); // expected-error {{is more lax}}
|
||||||
|
void g() noexcept (T::error);
|
||||||
|
};
|
||||||
|
|
||||||
|
Derived<Exc1> d1; // ok
|
||||||
|
Derived<Exc2> d2; // expected-note {{in instantiation of}}
|
||||||
|
|
Loading…
Reference in New Issue