diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c629a82a2cdc..a29ffce41e98 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -398,6 +398,11 @@ def warn_attribute_weak_import_invalid_on_definition : Warning< def warn_attribute_wrong_decl_type : Warning< "'%0' attribute only applies to %select{function|union|" "variable and function|function or method}1 types">; +def warn_gnuc_inline_attribute_requires_inline : Warning< + "'gnuc_inline' attribute requires function to be marked 'inline'," + " attribute ignored">; +def warn_gnuc_inline_attribute_extern_inline : Warning< + "'gnuc_inline' attribute is overridden by 'extern inline', attribute ignored">; def warn_attribute_ignored_for_field_of_type : Warning< "%0 attribute ignored for field of type %1">; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5b611e1d18ad..cafa67fde751 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -391,7 +391,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, return; } - if (!isFunctionOrMethod(d)) { + if (!isa(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "always_inline" << 0 /*function*/; return; @@ -485,8 +485,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { priority = Idx.getZExtValue(); } - FunctionDecl *Fn = dyn_cast(d); - if (!Fn) { + if (!isa(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "constructor" << 0 /*function*/; return; @@ -1447,7 +1446,7 @@ static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isFunctionOrMethod(d)) { + if (!isa(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "noinline" << 0 /*function*/; return; @@ -1463,12 +1462,23 @@ static void HandleGNUCInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isFunctionOrMethod(d)) { + FunctionDecl *Fn = dyn_cast(d); + if (Fn == 0) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "gnuc_inline" << 0 /*function*/; return; } + if (!Fn->isInline()) { + S.Diag(Attr.getLoc(), diag::warn_gnuc_inline_attribute_requires_inline); + return; + } + + if (Fn->getStorageClass() == FunctionDecl::Extern) { + S.Diag(Attr.getLoc(), diag::warn_gnuc_inline_attribute_extern_inline); + return; + } + d->addAttr(::new (S.Context) GNUCInlineAttr()); } diff --git a/clang/test/Sema/function.c b/clang/test/Sema/function.c index e604d0e1ea14..3a0352d75394 100644 --- a/clang/test/Sema/function.c +++ b/clang/test/Sema/function.c @@ -61,3 +61,12 @@ void f1static() { struct incomplete_test a(void) {} // expected-error{{incomplete result type 'struct incomplete_test' in function definition}} \ // expected-note{{forward declaration of 'struct incomplete_test'}} + + +extern __inline +__attribute__((__gnuc_inline__)) // expected-warning{{'gnuc_inline' attribute is overridden by 'extern inline', attribute ignored}} expected-warning{{extension used}} +void gnu_inline1() {} + +void +__attribute__((__gnuc_inline__)) // expected-warning {{'gnuc_inline' attribute requires function to be marked 'inline', attribute ignored}} expected-warning{{extension used}} +gnu_inline2() {}