ExtProtoInfo() :
Variadic(false), HasTrailingReturn(false), TypeQuals(0),
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) {}
FunctionType::ExtInfo ExtInfo;
const QualType *Exceptions;
Expr *NoexceptExpr;
FunctionDecl *ExceptionSpecDecl;
+ FunctionDecl *ExceptionSpecTemplate;
const bool *ConsumedArguments;
};
// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
// to the expression in the noexcept() specifier.
- // ExceptionSpecDecl - Instead of Exceptions, there may be a single
- // FunctionDecl* pointing to the function which should be used to resolve
- // this function type's exception specification.
+ // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may
+ // be a pair of FunctionDecl* pointing to the function which should be used to
+ // instantiate this function type's exception specification, and the function
+ // from which it should be instantiated.
// ConsumedArgs - A variable size array, following Exceptions
// and of length NumArgs, holding flags indicating which arguments
EPI.NoexceptExpr = getNoexceptExpr();
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
+ EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();
}
if (hasAnyConsumedArgs())
EPI.ConsumedArguments = getConsumedArgsBuffer();
// NoexceptExpr sits where the arguments 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 {
if (getExceptionSpecType() != EST_Uninstantiated)
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 {
ExceptionSpecificationType EST = getExceptionSpecType();
else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
Size += sizeof(Expr*);
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
- Size += sizeof(FunctionDecl*);
+ Size += 2 * sizeof(FunctionDecl*);
}
if (EPI.ConsumedArguments)
Size += NumArgs * sizeof(bool);
// Store the function decl from which we will resolve our
// exception specification.
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
// it's not instantiated as part of instantiating the type.
}
// Instantiate the exception specification for any function which is
// used: CodeGen will need it.
- if (Func->getTemplateInstantiationPattern() &&
- Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
- == EST_Uninstantiated)
+ const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
+ if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated)
InstantiateExceptionSpec(Loc, Func);
// Implicit instantiation of function templates and member functions of
static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &TemplateArgs) {
+ assert(Proto->getExceptionSpecType() != EST_Uninstantiated);
+
// C++11 [expr.prim.general]p3:
// If a declaration declares a member function or member function
// template of a class X, the expression this is a prvalue of type
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionDecl *Decl) {
- // Find the template declaration which contains the exception specification.
- // Per [except.spec]p4, prefer the exception spec on the primary template
- // 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)
+ const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>();
+ if (Proto->getExceptionSpecType() != EST_Uninstantiated)
return;
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
MultiLevelTemplateArgumentList TemplateArgs =
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, Proto, TemplateArgs);
+ ::InstantiateExceptionSpec(*this, Decl,
+ Template->getType()->castAs<FunctionProtoType>(),
+ TemplateArgs);
}
/// \brief Initializes the common fields of an instantiation function
EPI.ExceptionSpecType != EST_None &&
EPI.ExceptionSpecType != EST_DynamicNone &&
EPI.ExceptionSpecType != EST_BasicNoexcept) {
+ FunctionDecl *ExceptionSpecTemplate = Tmpl;
+ if (EPI.ExceptionSpecType == EST_Uninstantiated)
+ ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
+
// Mark the function has having an uninstantiated exception specification.
const FunctionProtoType *NewProto
= New->getType()->getAs<FunctionProtoType>();
EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_Uninstantiated;
EPI.ExceptionSpecDecl = New;
+ EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
NewProto->arg_type_begin(),
NewProto->getNumArgs(),
void 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 {
static void f() noexcept(sizeof(T) == 4) { h(); }
+ static void g() noexcept(sizeof(T) == 4);
};
// CHECK: define {{.*}} @_Z1fIsEvv() {
// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind
template void S<char16_t[2]>::f();
-void g() {
+void h() {
// CHECK: define {{.*}} @_Z1fIiEvv() nounwind {
f<int>();
// CHECK: define {{.*}} @_Z1fIA2_iEvv() {
// CHECK-NOT: nounwind
(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>();
+}
-// 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
// instantiated when it is needed.
decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
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))); // \
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}}