r341499 - PR38627: Fix handling of exception specification adjustment for

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 5 15:30:37 PDT 2018


Author: rsmith
Date: Wed Sep  5 15:30:37 2018
New Revision: 341499

URL: http://llvm.org/viewvc/llvm-project?rev=341499&view=rev
Log:
PR38627: Fix handling of exception specification adjustment for
destructors.

We previously tried to patch up the exception specification after
completing the class, which went wrong when the exception specification
was needed within the class body (in particular, by a friend
redeclaration of the destructor in a nested class). We now mark the
destructor as having a not-yet-computed exception specification
immediately after creating it.

This requires delaying various checks against the exception
specification (where we'd previously have just got the wrong exception
specification, and now find we have an exception specification that we
can't compute yet) when those checks fire while the class is being
defined.

This also exposed an issue that we were missing a CodeSynthesisContext
for computation of exception specifications (otherwise we'd fail to make
the module containing the definition of the class visible when computing
its members' exception specs). Adding that incidentally also gives us a
diagnostic quality improvement.

This has also exposed an pre-existing problem: making the exception
specification evaluation context a non-SFINAE context (as it should be)
results in a bootstrap failure; PR38850 filed for this.

Added:
    cfe/trunk/test/Modules/exception-spec.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/drs/dr13xx.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
    cfe/trunk/test/Modules/cxx-templates.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
    cfe/trunk/test/SemaCXX/exception-spec.cpp
    cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
    cfe/trunk/test/SemaCXX/member-init.cpp
    cfe/trunk/test/SemaTemplate/instantiate-init.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep  5 15:30:37 2018
@@ -1467,6 +1467,10 @@ def err_noexcept_needs_constant_expressi
   "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<
@@ -4270,6 +4274,8 @@ def note_forward_template_decl : Note<
 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">;
@@ -7471,8 +7477,6 @@ def note_in_class_initializer_not_yet_pa
   "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; "

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Sep  5 15:30:37 2018
@@ -608,7 +608,15 @@ public:
   /// 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
@@ -4872,8 +4880,7 @@ public:
   ///
   /// 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,
@@ -7142,6 +7149,10 @@ public:
       /// 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,
@@ -10635,7 +10646,9 @@ private:
     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 "
@@ -10647,13 +10660,19 @@ private:
 
   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);

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Wed Sep  5 15:30:37 2018
@@ -341,6 +341,8 @@ private:
       return "PriorTemplateArgumentSubstitution";
     case CodeSynthesisContext::DefaultTemplateArgumentChecking:
       return "DefaultTemplateArgumentChecking";
+    case CodeSynthesisContext::ExceptionSpecEvaluation:
+      return "ExceptionSpecEvaluation";
     case CodeSynthesisContext::ExceptionSpecInstantiation:
       return "ExceptionSpecInstantiation";
     case CodeSynthesisContext::DeclaringSpecialMember:

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Wed Sep  5 15:30:37 2018
@@ -922,10 +922,9 @@ void Sema::ActOnEndOfTranslationUnit() {
 
   // 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());

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Sep  5 15:30:37 2018
@@ -7956,14 +7956,11 @@ static FunctionDecl* CreateNewFunctionDe
                                     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;
@@ -15810,13 +15807,6 @@ void Sema::ActOnFields(Scope *S, SourceL
       }
 
       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);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Sep  5 15:30:37 2018
@@ -6635,20 +6635,27 @@ void Sema::CheckExplicitlyDefaultedMembe
 }
 
 void Sema::CheckDelayedMemberExceptionSpecs() {
-  decltype(DelayedExceptionSpecChecks) Checks;
-  decltype(DelayedDefaultedMemberExceptionSpecs) Specs;
-
-  std::swap(Checks, DelayedExceptionSpecChecks);
-  std::swap(Specs, DelayedDefaultedMemberExceptionSpecs);
+  decltype(DelayedOverridingExceptionSpecChecks) Overriding;
+  decltype(DelayedEquivalentExceptionSpecChecks) Equivalent;
+  decltype(DelayedDefaultedMemberExceptionSpecs) Defaulted;
+
+  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);
 }
 
@@ -10685,19 +10692,48 @@ void SpecialMemberExceptionSpecInfo::vis
     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,
@@ -11172,8 +11208,9 @@ void Sema::ActOnFinishCXXMemberDecls() {
   // 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);
@@ -11195,11 +11232,13 @@ void Sema::referenceDLLExportedClassMeth
   }
 }
 
-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-

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Wed Sep  5 15:30:37 2018
@@ -230,6 +230,16 @@ Sema::UpdateExceptionSpec(FunctionDecl *
     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,
@@ -278,6 +288,14 @@ bool Sema::CheckEquivalentExceptionSpec(
     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(
@@ -904,26 +922,21 @@ bool Sema::CheckOverridingFunctionExcept
   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;

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Sep  5 15:30:37 2018
@@ -199,6 +199,7 @@ bool Sema::CodeSynthesisContext::isInsta
   case DefaultTemplateArgumentChecking:
   case DeclaringSpecialMember:
   case DefiningSynthesizedFunction:
+  case ExceptionSpecEvaluation:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -621,6 +622,12 @@ void Sema::PrintInstantiationStack() {
       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)
@@ -695,6 +702,12 @@ Optional<TemplateDeductionInfo *> Sema::
       // 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;
     }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Sep  5 15:30:37 2018
@@ -3690,6 +3690,9 @@ TemplateDeclInstantiator::InitMethodInst
   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);

Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr13xx.cpp Wed Sep  5 15:30:37 2018
@@ -226,10 +226,10 @@ namespace dr1330 { // dr1330: 4 c++11
 #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

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp Wed Sep  5 15:30:37 2018
@@ -139,11 +139,11 @@ namespace NonLocalLambdaInstantation {
   }
 
   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}}
 }

Modified: cfe/trunk/test/Modules/cxx-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/Modules/cxx-templates.cpp (original)
+++ cfe/trunk/test/Modules/cxx-templates.cpp Wed Sep  5 15:30:37 2018
@@ -199,6 +199,8 @@ namespace hidden_specializations {
     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 at cxx-templates-unimported.h:29 {{explicit specialization of 'nested_cls_t' must be imported}}
+    // expected-note at -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

Added: cfe/trunk/test/Modules/exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/exception-spec.cpp?rev=341499&view=auto
==============================================================================
--- cfe/trunk/test/Modules/exception-spec.cpp (added)
+++ cfe/trunk/test/Modules/exception-spec.cpp Wed Sep  5 15:30:37 2018
@@ -0,0 +1,36 @@
+// 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

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Sep  5 15:30:37 2018
@@ -1972,9 +1972,9 @@ namespace ZeroSizeTypes {
 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

Modified: cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp Wed Sep  5 15:30:37 2018
@@ -99,8 +99,6 @@ namespace DefaultedFnExceptionSpec {
 
   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;
@@ -109,9 +107,9 @@ namespace DefaultedFnExceptionSpec {
   // 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) {

Modified: cfe/trunk/test/SemaCXX/exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exception-spec.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/exception-spec.cpp Wed Sep  5 15:30:37 2018
@@ -5,3 +5,50 @@ namespace MissingOnTemplate {
   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}}
+  };
+}

Modified: cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp Wed Sep  5 15:30:37 2018
@@ -16,41 +16,39 @@ namespace InClassInitializers {
   // 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}}
   };
 }

Modified: cfe/trunk/test/SemaCXX/member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-init.cpp Wed Sep  5 15:30:37 2018
@@ -13,10 +13,10 @@ public:
 
 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;
 };
 
@@ -127,19 +127,19 @@ A::A() {}
 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}}
 };
 }
 
@@ -147,17 +147,17 @@ namespace member_template {
 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}}
   };
 };
 }

Modified: cfe/trunk/test/SemaTemplate/instantiate-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-init.cpp?rev=341499&r1=341498&r2=341499&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-init.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-init.cpp Wed Sep  5 15:30:37 2018
@@ -115,8 +115,10 @@ namespace PR13064 {
   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 {




More information about the cfe-commits mailing list