]> granicus.if.org Git - clang/commitdiff
[Sema] Warn on attribute nothrow conflicting with language specifiers
authorErich Keane <erich.keane@intel.com>
Thu, 28 Sep 2017 20:36:53 +0000 (20:36 +0000)
committerErich Keane <erich.keane@intel.com>
Thu, 28 Sep 2017 20:36:53 +0000 (20:36 +0000)
I discovered it was possible to create a 'nothrow' noexcept(false)
function, which is both non-sensical as well as seemingly breaking.

This patch warns if attribute nothrow is used with anything besides "noexcept".

"noexcept(true)" isn't possible, because the noexcept decl isn't parsed until
later.

Differential Revision: https://reviews.llvm.org/D38205

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314461 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclAttr.cpp
test/SemaCXX/warn-conflicting-nothrow-attr-exception-spec.cpp [new file with mode: 0644]

index 0b3c9fed6bdb041c27e009a1f99d1831bcf6deef..d648d2f45f422dcb5d95991cfd285ac21f687a8e 100644 (file)
@@ -1407,6 +1407,10 @@ def err_noexcept_needs_constant_expression : Error<
   "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 warn_nothrow_attr_disagrees_with_exception_specification
+    : ExtWarn<"attribute 'nothrow' ignored due to conflicting exception "
+              "specification">,
+      InGroup<IgnoredAttributes>;
 
 // C++ access checking
 def err_class_redeclared_with_different_access : Error<
index 1f4be4405b557502fac694350c244b8ed65d3772..2a13c9576c79c0cbced15474ff1b9d637cc99229 100644 (file)
@@ -1985,6 +1985,25 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
       Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
 }
 
+static void handleNoThrowAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
+  assert(isa<FunctionDecl>(D) && "attribute nothrow only valid on functions");
+
+  auto *FD = cast<FunctionDecl>(D);
+  const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
+
+  if (FPT && FPT->hasExceptionSpec() &&
+      FPT->getExceptionSpecType() != EST_BasicNoexcept) {
+    S.Diag(Attrs.getLoc(),
+           diag::warn_nothrow_attr_disagrees_with_exception_specification);
+    S.Diag(FD->getExceptionSpecSourceRange().getBegin(),
+           diag::note_previous_decl)
+        << "exception specification";
+  }
+
+  D->addAttr(::new (S.Context) NoThrowAttr(
+      Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+}
+
 static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D,
                                         const AttributeList &Attr) {
   if (S.CheckNoCallerSavedRegsAttr(Attr))
@@ -6211,7 +6230,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
     handleNoReturnAttr(S, D, Attr);
     break;
   case AttributeList::AT_NoThrow:
-    handleSimpleAttribute<NoThrowAttr>(S, D, Attr);
+    handleNoThrowAttr(S, D, Attr);
     break;
   case AttributeList::AT_CUDAShared:
     handleSharedAttr(S, D, Attr);
diff --git a/test/SemaCXX/warn-conflicting-nothrow-attr-exception-spec.cpp b/test/SemaCXX/warn-conflicting-nothrow-attr-exception-spec.cpp
new file mode 100644 (file)
index 0000000..c927c4f
--- /dev/null
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -fcxx-exceptions -fsyntax-only -Wexceptions -verify -std=c++14
+
+struct S {
+  //expected-warning@+2 {{attribute 'nothrow' ignored due to conflicting exception specification}}
+  //expected-note@+1 {{exception specification declared here}}
+  __attribute__((nothrow)) S() noexcept(true);
+  //expected-warning@+2 {{attribute 'nothrow' ignored due to conflicting exception specification}}
+  //expected-note@+1 {{exception specification declared here}}
+  __attribute__((nothrow)) void Func1() noexcept(false);
+  __attribute__((nothrow)) void Func3() noexcept;
+};
+
+void throwing() noexcept(false);
+void non_throwing(bool b = true) noexcept;
+
+template <typename Fn>
+struct T {
+    __attribute__((nothrow)) void f(Fn) noexcept(Fn());
+};
+
+//expected-warning@-3 {{attribute 'nothrow' ignored due to conflicting exception specification}}
+//expected-note@-4 {{exception specification declared here}}
+template struct T<decltype(throwing)>;
+template struct T<decltype(non_throwing)>;