forked from OSchip/llvm-project
[Sema] Warn on attribute nothrow conflicting with language specifiers
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 llvm-svn: 314461
This commit is contained in:
parent
8eec6dde6a
commit
c372e15c4e
|
@ -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<
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)>;
|
Loading…
Reference in New Issue