Delay checking overrides for exception specifications if the overridden
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 22 Nov 2014 03:09:05 +0000 (03:09 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 22 Nov 2014 03:09:05 +0000 (03:09 +0000)
specification has not yet been parsed.

llvm-svn: 222603

clang/include/clang/Sema/Sema.h
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExceptionSpec.cpp
clang/test/CXX/except/except.spec/p5-delayed.cpp [new file with mode: 0644]

index 8b13b9d..92a4a47 100644 (file)
@@ -458,12 +458,11 @@ public:
   /// cycle detection at the end of the TU.
   DelegatingCtorDeclsType DelegatingCtorDecls;
 
-  /// \brief All the overriding destructors seen during a class definition
-  /// (there could be multiple due to nested classes) that had their exception
-  /// spec checks delayed, plus the overridden destructor.
-  SmallVector<std::pair<const CXXDestructorDecl*,
-                              const CXXDestructorDecl*>, 2>
-      DelayedDestructorExceptionSpecChecks;
+  /// \brief All the overriding functions seen during a class definition
+  /// that had their exception spec checks delayed, plus the overridden
+  /// function.
+  SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2>
+    DelayedExceptionSpecChecks;
 
   /// \brief All the members seen during a class definition which were both
   /// explicitly defaulted and had explicitly-specified exception
index 61ee770..b9aaf16 100644 (file)
@@ -680,7 +680,7 @@ void Sema::ActOnEndOfTranslationUnit() {
   // All delayed member exception specs should be checked or we end up accepting
   // incompatible declarations.
   assert(DelayedDefaultedMemberExceptionSpecs.empty());
-  assert(DelayedDestructorExceptionSpecChecks.empty());
+  assert(DelayedExceptionSpecChecks.empty());
 
   // Remove file scoped decls that turned out to be used.
   UnusedFileScopedDecls.erase(
index 90ca97b..ec62534 100644 (file)
@@ -5340,27 +5340,21 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
 }
 
 void Sema::CheckDelayedMemberExceptionSpecs() {
-  SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>,
-              2> Checks;
-  SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 2> Specs;
+  decltype(DelayedExceptionSpecChecks) Checks;
+  decltype(DelayedDefaultedMemberExceptionSpecs) Specs;
 
-  std::swap(Checks, DelayedDestructorExceptionSpecChecks);
+  std::swap(Checks, DelayedExceptionSpecChecks);
   std::swap(Specs, DelayedDefaultedMemberExceptionSpecs);
 
   // Perform any deferred checking of exception specifications for virtual
   // destructors.
-  for (unsigned i = 0, e = Checks.size(); i != e; ++i) {
-    const CXXDestructorDecl *Dtor = Checks[i].first;
-    assert(!Dtor->getParent()->isDependentType() &&
-           "Should not ever add destructors of templates into the list.");
-    CheckOverridingFunctionExceptionSpec(Dtor, Checks[i].second);
-  }
+  for (auto &Check : Checks)
+    CheckOverridingFunctionExceptionSpec(Check.first, Check.second);
 
   // Check that any explicitly-defaulted methods have exception specifications
   // compatible with their implicit exception specifications.
-  for (unsigned I = 0, N = Specs.size(); I != N; ++I)
-    CheckExplicitlyDefaultedMemberExceptionSpec(Specs[I].first,
-                                                Specs[I].second);
+  for (auto &Spec : Specs)
+    CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second);
 }
 
 namespace {
@@ -9298,7 +9292,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
   if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
     if (Record->isInvalidDecl()) {
       DelayedDefaultedMemberExceptionSpecs.clear();
-      DelayedDestructorExceptionSpecChecks.clear();
+      DelayedExceptionSpecChecks.clear();
       return;
     }
   }
index 7175c01..2387325 100644 (file)
@@ -801,6 +801,11 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
 
 bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
                                                 const CXXMethodDecl *Old) {
+  // If the new exception specification hasn't been parsed yet, skip the check.
+  // We'll get called again once it's been parsed.
+  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.
@@ -809,16 +814,18 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
     if (New->getParent()->isBeingDefined()) {
       // The destructor might be updated once the definition is finished. So
       // remember it and check later.
-      DelayedDestructorExceptionSpecChecks.push_back(std::make_pair(
-        cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old)));
+      DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
       return false;
     }
   }
-  // If the exception specification hasn't been parsed yet, skip the check.
-  // We'll get called again once it's been parsed.
-  if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
-      EST_Unparsed)
+  // 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
+  // lexically-surrounding class.
+  if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
+      EST_Unparsed) {
+    DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
     return false;
+  }
   unsigned DiagID = diag::err_override_exception_spec;
   if (getLangOpts().MicrosoftExt)
     DiagID = diag::ext_override_exception_spec;
diff --git a/clang/test/CXX/except/except.spec/p5-delayed.cpp b/clang/test/CXX/except/except.spec/p5-delayed.cpp
new file mode 100644 (file)
index 0000000..99c0e2d
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -fexceptions -fcxx-exceptions
+
+struct A { struct X { virtual ~X() throw(Y); }; struct Y : X {}; };
+struct B { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(Y); }; };
+struct C { struct X { virtual void f() throw(Y); }; struct Y : X { void f() throw(); }; };
+struct D { struct X { virtual void f() throw(Y); }; struct Y : X { void f() noexcept; }; };
+struct E { struct Y; struct X { virtual Y &operator=(const Y&) throw(Y); }; struct Y : X {}; };
+struct F {
+  struct X {
+    virtual void f() throw(Y); // expected-note {{here}}
+  };
+  struct Y : X {
+    void f() throw(int); // expected-error {{more lax}}
+  };
+};