llvm-project/clang/test/SemaCXX/implicit-exception-spec.cpp

96 lines
3.0 KiB
C++
Raw Normal View History

// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s
template<bool b> struct ExceptionIf { static int f(); };
template<> struct ExceptionIf<false> { typedef int f; };
// The exception specification of a defaulted default constructor depends on
// the contents of in-class member initializers. However, the in-class member
// initializers can depend on the exception specification of the constructor,
// since the class is considered complete within them. We reject any such cases.
namespace InClassInitializers {
// Noexcept::Noexcept() is implicitly declared as noexcept(false), because it
// directly invokes ThrowSomething(). However...
//
// If noexcept(Noexcept()) is false, then Noexcept() is a constant expression,
// so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then
// Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
// is false.
bool ThrowSomething() noexcept(false);
struct ConstExpr {
Final piece of core issue 1330: delay computing the exception specification of a defaulted special member function until the exception specification is needed (using the same criteria used for the delayed instantiation of exception specifications for function temploids). EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to resolve the exception specification. This is enabled for all C++ modes: it's a little faster in the case where the exception specification isn't used, allows our C++11-in-C++98 extensions to work, and is still correct for C++98, since in that mode the computation of the exception specification can't fail. The diagnostics here aren't great (in particular, we should include implicit evaluation of exception specifications for defaulted special members in the template instantiation backtraces), but they're not much worse than before. Our approach to the problem of cycles between in-class initializers and the exception specification for a defaulted default constructor is modified a little by this change -- we now reject any odr-use of a defaulted default constructor if that constructor uses an in-class initializer and the use is in an in-class initialzer which is declared lexically earlier. This is a closer approximation to the current draft solution in core issue 1351, but isn't an exact match (but the current draft wording isn't reasonable, so that's to be expected). llvm-svn: 160847
2012-07-27 12:22:15 +08:00
bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot be used by non-static data member initializer}}
};
// We can use it now.
bool w = noexcept(ConstExpr());
// Much more obviously broken: we can't parse the initializer without already
// knowing whether it produces a noexcept expression.
struct TemplateArg {
Final piece of core issue 1330: delay computing the exception specification of a defaulted special member function until the exception specification is needed (using the same criteria used for the delayed instantiation of exception specifications for function temploids). EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to resolve the exception specification. This is enabled for all C++ modes: it's a little faster in the case where the exception specification isn't used, allows our C++11-in-C++98 extensions to work, and is still correct for C++98, since in that mode the computation of the exception specification can't fail. The diagnostics here aren't great (in particular, we should include implicit evaluation of exception specifications for defaulted special members in the template instantiation backtraces), but they're not much worse than before. Our approach to the problem of cycles between in-class initializers and the exception specification for a defaulted default constructor is modified a little by this change -- we now reject any odr-use of a defaulted default constructor if that constructor uses an in-class initializer and the use is in an in-class initialzer which is declared lexically earlier. This is a closer approximation to the current draft solution in core issue 1351, but isn't an exact match (but the current draft wording isn't reasonable, so that's to be expected). llvm-svn: 160847
2012-07-27 12:22:15 +08:00
int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{cannot be used by non-static data member initializer}}
};
bool x = noexcept(TemplateArg());
// And within a nested class.
struct Nested { // expected-error {{cannot be used by non-static data member initializer}}
struct Inner {
int n = ExceptionIf<noexcept(Nested())>::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}}
} inner;
};
Final piece of core issue 1330: delay computing the exception specification of a defaulted special member function until the exception specification is needed (using the same criteria used for the delayed instantiation of exception specifications for function temploids). EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to resolve the exception specification. This is enabled for all C++ modes: it's a little faster in the case where the exception specification isn't used, allows our C++11-in-C++98 extensions to work, and is still correct for C++98, since in that mode the computation of the exception specification can't fail. The diagnostics here aren't great (in particular, we should include implicit evaluation of exception specifications for defaulted special members in the template instantiation backtraces), but they're not much worse than before. Our approach to the problem of cycles between in-class initializers and the exception specification for a defaulted default constructor is modified a little by this change -- we now reject any odr-use of a defaulted default constructor if that constructor uses an in-class initializer and the use is in an in-class initialzer which is declared lexically earlier. This is a closer approximation to the current draft solution in core issue 1351, but isn't an exact match (but the current draft wording isn't reasonable, so that's to be expected). llvm-svn: 160847
2012-07-27 12:22:15 +08:00
struct Nested2 {
struct Inner;
int n = Inner().n; // expected-error {{cannot be used by non-static data member initializer}}
struct Inner {
int n = ExceptionIf<noexcept(Nested2())>::f();
Final piece of core issue 1330: delay computing the exception specification of a defaulted special member function until the exception specification is needed (using the same criteria used for the delayed instantiation of exception specifications for function temploids). EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to resolve the exception specification. This is enabled for all C++ modes: it's a little faster in the case where the exception specification isn't used, allows our C++11-in-C++98 extensions to work, and is still correct for C++98, since in that mode the computation of the exception specification can't fail. The diagnostics here aren't great (in particular, we should include implicit evaluation of exception specifications for defaulted special members in the template instantiation backtraces), but they're not much worse than before. Our approach to the problem of cycles between in-class initializers and the exception specification for a defaulted default constructor is modified a little by this change -- we now reject any odr-use of a defaulted default constructor if that constructor uses an in-class initializer and the use is in an in-class initialzer which is declared lexically earlier. This is a closer approximation to the current draft solution in core issue 1351, but isn't an exact match (but the current draft wording isn't reasonable, so that's to be expected). llvm-svn: 160847
2012-07-27 12:22:15 +08:00
} inner;
};
}
namespace ExceptionSpecification {
// A type is permitted to be used in a dynamic exception specification when it
// is still being defined, but isn't complete within such an exception
// specification.
struct Nested { // expected-note {{not complete}}
struct T {
T() noexcept(!noexcept(Nested())); // expected-error{{incomplete type}}
} t;
};
}
namespace DefaultArgument {
struct Default {
struct T {
T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}}
} t; // expected-note {{has no default constructor}}
};
}
namespace ImplicitDtorExceptionSpec {
struct A {
virtual ~A();
struct Inner {
~Inner() throw();
};
Inner inner;
};
struct B {
virtual ~B() {} // expected-note {{here}}
};
struct C : B {
virtual ~C() {}
A a;
};
struct D : B {
~D(); // expected-error {{more lax than base}}
struct E {
~E();
struct F {
~F() throw(A);
} f;
} e;
};
}