"argument to noexcept specifier must be a constant expression">;
def err_exception_spec_not_parsed : Error<
"exception specification is not available until end of class definition">;
+def err_exception_spec_cycle : Error<
+ "exception specification of %0 uses itself">;
+def err_exception_spec_incomplete_type : Error<
+ "exception specification needed for member of incomplete class %0">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
def note_inst_declaration_hint : Note<"add an explicit instantiation "
"declaration to suppress this warning if %q0 is explicitly instantiated in "
"another translation unit">;
+def note_evaluating_exception_spec_here : Note<
+ "in evaluation of exception specification for %q0 needed here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
"default member initializer declared here">;
def err_in_class_initializer_cycle
: Error<"default member initializer for %0 uses itself">;
-def err_exception_spec_cycle
- : Error<"exception specification of %0 uses itself">;
def ext_in_class_initializer_non_constant : Extension<
"in-class initializer for static data member is not a constant expression; "
/// that had their exception spec checks delayed, plus the overridden
/// function.
SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2>
- DelayedExceptionSpecChecks;
+ DelayedOverridingExceptionSpecChecks;
+
+ /// All the function redeclarations seen during a class definition that had
+ /// their exception spec checks delayed, plus the prior declaration they
+ /// should be checked against. Except during error recovery, the new decl
+ /// should always be a friend declaration, as that's the only valid way to
+ /// redeclare a special member before its class is complete.
+ SmallVector<std::pair<FunctionDecl*, FunctionDecl*>, 2>
+ DelayedEquivalentExceptionSpecChecks;
/// All the members seen during a class definition which were both
/// explicitly defaulted and had explicitly-specified exception
///
/// C++11 says that user-defined destructors with no exception spec get one
/// that looks as if the destructor was implicitly declared.
- void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
- CXXDestructorDecl *Destructor);
+ void AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor);
/// Define the specified inheriting constructor.
void DefineInheritingConstructor(SourceLocation UseLoc,
/// has been used when naming a template-id.
DefaultTemplateArgumentChecking,
+ /// We are computing the exception specification for a defaulted special
+ /// member function.
+ ExceptionSpecEvaluation,
+
/// We are instantiating the exception specification for a function
/// template which was deferred until it was needed.
ExceptionSpecInstantiation,
SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); }
~SavePendingParsedClassStateRAII() {
- assert(S.DelayedExceptionSpecChecks.empty() &&
+ assert(S.DelayedOverridingExceptionSpecChecks.empty() &&
+ "there shouldn't be any pending delayed exception spec checks");
+ assert(S.DelayedEquivalentExceptionSpecChecks.empty() &&
"there shouldn't be any pending delayed exception spec checks");
assert(S.DelayedDefaultedMemberExceptionSpecs.empty() &&
"there shouldn't be any pending delayed defaulted member "
private:
Sema &S;
- decltype(DelayedExceptionSpecChecks) SavedExceptionSpecChecks;
+ decltype(DelayedOverridingExceptionSpecChecks)
+ SavedOverridingExceptionSpecChecks;
+ decltype(DelayedEquivalentExceptionSpecChecks)
+ SavedEquivalentExceptionSpecChecks;
decltype(DelayedDefaultedMemberExceptionSpecs)
SavedDefaultedMemberExceptionSpecs;
decltype(DelayedDllExportClasses) SavedDllExportClasses;
void swapSavedState() {
- SavedExceptionSpecChecks.swap(S.DelayedExceptionSpecChecks);
+ SavedOverridingExceptionSpecChecks.swap(
+ S.DelayedOverridingExceptionSpecChecks);
+ SavedEquivalentExceptionSpecChecks.swap(
+ S.DelayedEquivalentExceptionSpecChecks);
SavedDefaultedMemberExceptionSpecs.swap(
S.DelayedDefaultedMemberExceptionSpecs);
SavedDllExportClasses.swap(S.DelayedDllExportClasses);
return "PriorTemplateArgumentSubstitution";
case CodeSynthesisContext::DefaultTemplateArgumentChecking:
return "DefaultTemplateArgumentChecking";
+ case CodeSynthesisContext::ExceptionSpecEvaluation:
+ return "ExceptionSpecEvaluation";
case CodeSynthesisContext::ExceptionSpecInstantiation:
return "ExceptionSpecInstantiation";
case CodeSynthesisContext::DeclaringSpecialMember:
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
- // FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to
- // write out the lists to the AST file (if any).
+ assert(DelayedOverridingExceptionSpecChecks.empty());
+ assert(DelayedEquivalentExceptionSpecChecks.empty());
assert(DelayedDefaultedMemberExceptionSpecs.empty());
- assert(DelayedExceptionSpecChecks.empty());
// All dllexport classes should have been processed already.
assert(DelayedDllExportClasses.empty());
NameInfo, R, TInfo, isInline,
/*isImplicitlyDeclared=*/false);
- // If the class is complete, then we now create the implicit exception
- // specification. If the class is incomplete or dependent, we can't do
- // it yet.
- if (SemaRef.getLangOpts().CPlusPlus11 && !Record->isDependentType() &&
- Record->getDefinition() && !Record->isBeingDefined() &&
- R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
- SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
- }
+ // If the destructor needs an implicit exception specification, set it
+ // now. FIXME: It'd be nice to be able to create the right type to start
+ // with, but the type needs to reference the destructor declaration.
+ if (SemaRef.getLangOpts().CPlusPlus11)
+ SemaRef.AdjustDestructorExceptionSpec(NewDD);
IsVirtualOkay = true;
return NewDD;
}
if (!CXXRecord->isDependentType()) {
- if (CXXRecord->hasUserDeclaredDestructor()) {
- // Adjust user-defined destructor exception spec.
- if (getLangOpts().CPlusPlus11)
- AdjustDestructorExceptionSpec(CXXRecord,
- CXXRecord->getDestructor());
- }
-
// Add any implicitly-declared members to this class.
AddImplicitlyDeclaredMembersToClass(CXXRecord);
}
void Sema::CheckDelayedMemberExceptionSpecs() {
- decltype(DelayedExceptionSpecChecks) Checks;
- decltype(DelayedDefaultedMemberExceptionSpecs) Specs;
+ decltype(DelayedOverridingExceptionSpecChecks) Overriding;
+ decltype(DelayedEquivalentExceptionSpecChecks) Equivalent;
+ decltype(DelayedDefaultedMemberExceptionSpecs) Defaulted;
- std::swap(Checks, DelayedExceptionSpecChecks);
- std::swap(Specs, DelayedDefaultedMemberExceptionSpecs);
+ std::swap(Overriding, DelayedOverridingExceptionSpecChecks);
+ std::swap(Equivalent, DelayedEquivalentExceptionSpecChecks);
+ std::swap(Defaulted, DelayedDefaultedMemberExceptionSpecs);
// Perform any deferred checking of exception specifications for virtual
// destructors.
- for (auto &Check : Checks)
+ for (auto &Check : Overriding)
CheckOverridingFunctionExceptionSpec(Check.first, Check.second);
+ // Perform any deferred checking of exception specifications for befriended
+ // special members.
+ for (auto &Check : Equivalent)
+ CheckEquivalentExceptionSpec(Check.second, Check.first);
+
// Check that any explicitly-defaulted methods have exception specifications
// compatible with their implicit exception specifications.
- for (auto &Spec : Specs)
+ for (auto &Spec : Defaulted)
CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second);
}
ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD);
}
+namespace {
+/// RAII object to register a special member as being currently declared.
+struct ComputingExceptionSpec {
+ Sema &S;
+
+ ComputingExceptionSpec(Sema &S, CXXMethodDecl *MD, SourceLocation Loc)
+ : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
+ Ctx.PointOfInstantiation = Loc;
+ Ctx.Entity = MD;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~ComputingExceptionSpec() {
+ S.popCodeSynthesisContext();
+ }
+};
+}
+
static Sema::ImplicitExceptionSpecification
ComputeDefaultedSpecialMemberExceptionSpec(
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
Sema::InheritedConstructorInfo *ICI) {
+ ComputingExceptionSpec CES(S, MD, Loc);
+
CXXRecordDecl *ClassDecl = MD->getParent();
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
- SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc);
+ SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, MD->getLocation());
if (ClassDecl->isInvalidDecl())
return Info.ExceptSpec;
+ // FIXME: If this diagnostic fires, we're probably missing a check for
+ // attempting to resolve an exception specification before it's known
+ // at a higher level.
+ if (S.RequireCompleteType(MD->getLocation(),
+ S.Context.getRecordType(ClassDecl),
+ diag::err_exception_spec_incomplete_type))
+ return Info.ExceptSpec;
+
// C++1z [except.spec]p7:
// [Look for exceptions thrown by] a constructor selected [...] to
// initialize a potentially constructed subobject,
// If the context is an invalid C++ class, just suppress these checks.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
if (Record->isInvalidDecl()) {
+ DelayedOverridingExceptionSpecChecks.clear();
+ DelayedEquivalentExceptionSpecChecks.clear();
DelayedDefaultedMemberExceptionSpecs.clear();
- DelayedExceptionSpecChecks.clear();
return;
}
checkForMultipleExportedDefaultConstructors(*this, Record);
}
}
-void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
- CXXDestructorDecl *Destructor) {
+void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
assert(getLangOpts().CPlusPlus11 &&
"adjusting dtor exception specs was introduced in c++11");
+ if (Destructor->isDependentContext())
+ return;
+
// C++11 [class.dtor]p3:
// A declaration of a destructor that does not have an exception-
// specification is implicitly considered to have the same exception-
Context.adjustExceptionSpec(Redecl, ESI);
}
+static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) {
+ auto *MD = dyn_cast<CXXMethodDecl>(FD);
+ if (!MD)
+ return false;
+
+ auto EST = MD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType();
+ return EST == EST_Unparsed ||
+ (EST == EST_Unevaluated && MD->getParent()->isBeingDefined());
+};
+
static bool CheckEquivalentExceptionSpecImpl(
Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
ReturnValueOnError = false;
}
+ // If we're befriending a member function of a class that's currently being
+ // defined, we might not be able to work out its exception specification yet.
+ // If not, defer the check until later.
+ if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) {
+ DelayedEquivalentExceptionSpecChecks.push_back({New, Old});
+ return false;
+ }
+
// Check the types as written: they must match before any exception
// specification adjustment is applied.
if (!CheckEquivalentExceptionSpecImpl(
if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
EST_Unparsed)
return false;
- if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
- // Don't check uninstantiated template destructors at all. We can only
- // synthesize correct specs after the template is instantiated.
- if (New->getParent()->isDependentType())
- return false;
- if (New->getParent()->isBeingDefined()) {
- // The destructor might be updated once the definition is finished. So
- // remember it and check later.
- DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
- return false;
- }
- }
- // If the old exception specification hasn't been parsed yet, remember that
- // we need to perform this check when we get to the end of the outermost
+
+ // Don't check uninstantiated template destructors at all. We can only
+ // synthesize correct specs after the template is instantiated.
+ if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType())
+ return false;
+
+ // If the old exception specification hasn't been parsed yet, or the new
+ // exception specification can't be computed yet, remember that we need to
+ // perform this check when we get to the end of the outermost
// lexically-surrounding class.
- if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
- EST_Unparsed) {
- DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
+ if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) {
+ DelayedOverridingExceptionSpecChecks.push_back({New, Old});
return false;
}
+
unsigned DiagID = diag::err_override_exception_spec;
if (getLangOpts().MicrosoftExt)
DiagID = diag::ext_override_exception_spec;
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DefiningSynthesizedFunction:
+ case ExceptionSpecEvaluation:
return false;
// This function should never be called when Kind's value is Memoization.
break;
}
+ case CodeSynthesisContext::ExceptionSpecEvaluation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_evaluating_exception_spec_here)
+ << cast<FunctionDecl>(Active->Entity);
+ break;
+
case CodeSynthesisContext::ExceptionSpecInstantiation:
Diags.Report(Active->PointOfInstantiation,
diag::note_template_exception_spec_instantiation_here)
// there is no SFINAE.
return None;
+ case CodeSynthesisContext::ExceptionSpecEvaluation:
+ // FIXME: This should not be treated as a SFINAE context, because
+ // we will cache an incorrect exception specification. However, clang
+ // bootstrap relies this! See PR31692.
+ break;
+
case CodeSynthesisContext::Memoization:
break;
}
if (InitFunctionInstantiation(New, Tmpl))
return true;
+ if (isa<CXXDestructorDecl>(New) && SemaRef.getLangOpts().CPlusPlus11)
+ SemaRef.AdjustDestructorExceptionSpec(cast<CXXDestructorDecl>(New));
+
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten())
New->setVirtualAsWritten(true);
#endif
void f(D &d) { d = d; } // ok
- // FIXME: In C++11 onwards, we should also note the declaration of 'e' as the
- // line that triggers the use of E::E()'s exception specification.
struct E : C<int> {}; // expected-note {{in instantiation of}}
- E e;
+#if __cplusplus >= 201103L
+ E e; // expected-note {{needed here}}
+#endif
}
namespace dr1346 { // dr1346: 3.5
}
template<typename T>
- struct X2 {
+ struct X2 { // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x'}}
int x = []{ return T(); }(); // expected-error{{cannot initialize a member subobject of type 'int' with an rvalue of type 'int *'}}
};
X2<int> x2i;
X2<float> x2f;
- X2<int*> x2ip; // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x'}}
+ X2<int*> x2ip; // expected-note {{in evaluation of exception spec}}
}
cls<char*> uk4; // expected-error 1+{{partial specialization of 'cls<T *>' must be imported}} expected-error 1+{{definition of}}
cls<void>::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}}
cls<void>::nested_cls_t<int> unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
+ // expected-error@cxx-templates-unimported.h:29 {{explicit specialization of 'nested_cls_t' must be imported}}
+ // expected-note@-2 {{in evaluation of exception specification}}
cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}}
// For enums, uses that would trigger instantiations of definitions are not
--- /dev/null
+// RUN: %clang_cc1 -x c++ -std=c++17 -fmodules -fmodules-local-submodule-visibility -fmodules-cache-path=%t %s -verify
+
+// expected-no-diagnostics
+
+#pragma clang module build PR38627
+module PR38627 {}
+#pragma clang module contents
+#pragma clang module begin PR38627
+namespace PR38627 {
+struct X {
+ virtual ~X() {}
+ struct C {
+ friend X::~X();
+ } c;
+};
+}
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import PR38627
+
+namespace PR38627 {
+struct Y {
+ virtual ~Y() {}
+ struct C {
+ friend Y::~Y();
+ } c;
+};
+static_assert(noexcept(X().~X()));
+static_assert(noexcept(Y().~Y()));
+
+struct A { virtual ~A() = default; };
+struct B : public A, public X {
+ virtual ~B() override = default;
+};
+} // PR38627
namespace BadDefaultInit {
template<int N> struct X { static const int n = N; };
- struct A {
+ struct A { // expected-error {{default member initializer for 'k' needed within definition of enclosing class}}
int k = // expected-note {{default member initializer declared here}}
- X<A().k>::n; // expected-error {{default member initializer for 'k' needed within definition of enclosing class}}
+ X<A().k>::n; // expected-note {{in evaluation of exception specification for 'BadDefaultInit::A::A' needed here}}
};
// FIXME: The "constexpr constructor must initialize all members" diagnostic
Error<char> c; // expected-note 2{{instantiation of}}
struct DelayImplicit {
- // FIXME: The location of this note is terrible. The instantiation was
- // triggered by the uses of the functions in the decltype expressions below.
Error<int> e; // expected-note 6{{instantiation of}}
};
Error<float> *e;
// a defaulted special member function that calls the function is needed.
// Use in an unevaluated operand still results in the exception spec being
// needed.
- void test1(decltype(declval<DelayImplicit>() = DelayImplicit(DelayImplicit())));
- void test2(decltype(declval<DelayImplicit>() = declval<const DelayImplicit>()));
- void test3(decltype(DelayImplicit(declval<const DelayImplicit>())));
+ void test1(decltype(declval<DelayImplicit>() = DelayImplicit(DelayImplicit()))); // expected-note 4{{in evaluation of exception specification}}
+ void test2(decltype(declval<DelayImplicit>() = declval<const DelayImplicit>())); // expected-note {{in evaluation of exception specification}}
+ void test3(decltype(DelayImplicit(declval<const DelayImplicit>()))); // expected-note {{in evaluation of exception specification}}
// Any odr-use needs the exception specification.
void f(Error<double> *p) {
template<typename T> void foo(T); // expected-error {{missing exception specification 'noexcept(true)'}}
void test() { foo(0); }
}
+
+struct UseBeforeComplete1 {
+ ~UseBeforeComplete1(); // expected-note {{previous}}
+ struct X {
+ friend UseBeforeComplete1::~UseBeforeComplete1() noexcept; // expected-warning {{previously declared with an implicit}}
+ };
+};
+
+struct ThrowingDtor { ~ThrowingDtor() noexcept(false); };
+struct UseBeforeComplete2 {
+ ~UseBeforeComplete2(); // expected-note {{previous}}
+ struct X {
+ friend UseBeforeComplete2::~UseBeforeComplete2() noexcept; // expected-error {{does not match previous}}
+ };
+ ThrowingDtor td;
+};
+
+struct UseBeforeComplete3 {
+ ~UseBeforeComplete3();
+ struct X {
+ friend UseBeforeComplete3::~UseBeforeComplete3(); // ok, implicitly noexcept(true)
+ };
+};
+static_assert(noexcept(UseBeforeComplete3()), "");
+
+struct UseBeforeComplete4 {
+ ~UseBeforeComplete4();
+ struct X {
+ friend UseBeforeComplete4::~UseBeforeComplete4(); // ok, implicitly noexcept(false)
+ };
+ ThrowingDtor td;
+};
+static_assert(!noexcept(UseBeforeComplete4()), "");
+
+namespace AssignmentOp {
+ struct D1;
+ struct D2;
+ struct B {
+ B &operator=(const B&);
+ virtual D1 &operator=(const D1&) noexcept; // expected-note {{overridden}}
+ virtual D2 &operator=(const D2&) noexcept; // expected-note {{overridden}}
+ };
+ struct D1 : B {}; // expected-error {{more lax}}
+ struct D2 : B {
+ D2 &operator=(const D2&); // expected-error {{more lax}}
+ };
+}
// Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
// is false.
bool ThrowSomething() noexcept(false);
- struct ConstExpr {
+ struct ConstExpr { // expected-error {{default member initializer for 'b' needed}}
bool b = // expected-note {{declared here}}
- noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{default member initializer for 'b' needed}}
+ noexcept(ConstExpr()) && ThrowSomething(); // expected-note {{in evaluation of exception spec}}
};
// Much more obviously broken: we can't parse the initializer without already
// knowing whether it produces a noexcept expression.
- struct TemplateArg {
+ struct TemplateArg { // expected-error {{default member initializer for 'n' needed}}
int n = // expected-note {{declared here}}
- ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{default member initializer for 'n' needed}}
+ ExceptionIf<noexcept(TemplateArg())>::f(); // expected-note {{in evaluation of exception spec}}
};
// And within a nested class.
struct Nested {
- struct Inner {
+ struct Inner { // expected-error {{default member initializer for 'n' needed}}
int n = // expected-note {{declared here}}
- ExceptionIf<noexcept(Nested())>::f();
- } inner; // expected-error {{default member initializer for 'n' needed}}
+ ExceptionIf<noexcept(Nested())>::f(); // expected-note {{in evaluation of exception spec}}
+ } inner; // expected-note {{in evaluation of exception spec}}
};
struct Nested2 {
struct Inner;
- int n = Inner().n; // expected-error {{initializer for 'n' needed}}
- struct Inner {
+ int n = Inner().n; // expected-note {{in evaluation of exception spec}}
+ struct Inner { // expected-error {{initializer for 'n' needed}}
int n = ExceptionIf<noexcept(Nested2())>::f(); // expected-note {{declared here}}
} inner;
};
}
namespace ExceptionSpecification {
- // FIXME: This diagnostic is quite useless; we should indicate whose
- // exception specification we were looking for and why.
struct Nested {
struct T {
- T() noexcept(!noexcept(Nested()));
+ T() noexcept(!noexcept(Nested())); // expected-note {{in evaluation of exception spec}}
} t; // expected-error{{exception specification is not available until end of class definition}}
};
}
bool b();
int k;
-struct Recurse {
+struct Recurse { // expected-error {{initializer for 'n' needed}}
int &n = // expected-note {{declared here}}
b() ?
- Recurse().n : // expected-error {{initializer for 'n' needed}}
+ Recurse().n : // expected-note {{in evaluation of exception spec}}
k;
};
namespace template_default_ctor {
struct A {
template <typename T>
- struct B {
+ struct B { // expected-error {{initializer for 'm1' needed}}
int m1 = 0; // expected-note {{declared here}}
};
- enum { NOE = noexcept(B<int>()) }; // expected-error {{initializer for 'm1' needed}}
+ enum { NOE = noexcept(B<int>()) }; // expected-note {{in evaluation of exception spec}}
};
}
namespace default_ctor {
struct A {
- struct B {
+ struct B { // expected-error {{initializer for 'm1' needed}}
int m1 = 0; // expected-note {{declared here}}
};
- enum { NOE = noexcept(B()) }; // expected-error {{initializer for 'm1' needed}}
+ enum { NOE = noexcept(B()) }; // expected-note {{in evaluation of exception spec}}
};
}
struct A {
template <typename T>
struct B {
- struct C {
+ struct C { // expected-error {{initializer for 'm1' needed}}
int m1 = 0; // expected-note {{declared here}}
};
template <typename U>
- struct D {
+ struct D { // expected-error {{initializer for 'm1' needed}}
int m1 = 0; // expected-note {{declared here}}
};
};
enum {
- NOE1 = noexcept(B<int>::C()), // expected-error {{initializer for 'm1' needed}}
- NOE2 = noexcept(B<int>::D<int>()) // expected-error {{initializer for 'm1' needed}}
+ NOE1 = noexcept(B<int>::C()), // expected-note {{in evaluation of exception spec}}
+ NOE2 = noexcept(B<int>::D<int>()) // expected-note {{in evaluation of exception spec}}
};
};
}
struct A { explicit A(int); }; // expected-note{{here}}
template<typename T> struct B { T a { 0 }; };
B<A> b;
- template<typename T> struct C { T a = { 0 }; }; // expected-error{{explicit}}
- C<A> c; // expected-note {{in instantiation of default member initializer}}
+ template <typename T> struct C { // expected-note {{in instantiation of default member initializer}}
+ T a = {0}; // expected-error{{explicit}}
+ };
+ C<A> c; // expected-note {{in evaluation of exception spec}}
}
namespace PR16903 {