summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2019-09-27 12:25:19 +0000
committerMartin Storsjo <martin@martin.st>2019-09-27 12:25:19 +0000
commit822f64eae96c73035a0890db1614d4ce2b792fa4 (patch)
tree860af53636238fc2fa4bfae269fd1fe0db2583b9
parent22929c361efd3edc4d6937ac6e30f2462ac3fa13 (diff)
downloadclang-822f64eae96c73035a0890db1614d4ce2b792fa4.tar.gz
[clang] [AST] Treat "inline gnu_inline" the same way as "extern inline gnu_inline" in C++ mode
This matches how GCC handles it, see e.g. https://gcc.godbolt.org/z/HPplnl. GCC documents the gnu_inline attribute with "In C++, this attribute does not depend on extern in any way, but it still requires the inline keyword to enable its special behavior." The previous behaviour of gnu_inline in C++, without the extern keyword, can be traced back to the original commit that added support for gnu_inline, SVN r69045. Differential Revision: https://reviews.llvm.org/D67414 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373078 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/ReleaseNotes.rst5
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--lib/AST/Decl.cpp8
-rw-r--r--lib/Sema/SemaDeclAttr.cpp3
-rw-r--r--test/CodeGen/inline.c3
-rw-r--r--test/SemaCUDA/gnu-inline.cu2
-rw-r--r--test/SemaCXX/gnu_inline.cpp9
-rw-r--r--test/SemaCXX/undefined-inline.cpp6
8 files changed, 31 insertions, 9 deletions
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 5dbc4a0415..91ae3071ff 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -128,7 +128,10 @@ C11 Feature Support
C++ Language Changes in Clang
-----------------------------
-- ...
+- The behaviour of the `gnu_inline` attribute now matches GCC, for cases
+ where used without the `extern` keyword. As this is a change compared to
+ how it behaved in previous Clang versions, a warning is emitted for this
+ combination.
C++1z Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c2cef944b6..adc658bb29 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3008,6 +3008,10 @@ def warn_gnu_inline_attribute_requires_inline : Warning<
"'gnu_inline' attribute requires function to be marked 'inline',"
" attribute ignored">,
InGroup<IgnoredAttributes>;
+def warn_gnu_inline_cplusplus_without_extern : Warning<
+ "'gnu_inline' attribute without 'extern' in C++ treated as externally"
+ " available, this changed in Clang 10">,
+ InGroup<DiagGroup<"gnu-inline-cpp-without-extern">>;
def err_attribute_vecreturn_only_vector_member : Error<
"the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">;
def err_attribute_vecreturn_only_pod_record : Error<
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e95338138f..19a012b332 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3261,6 +3261,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return true;
}
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
+
if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
// With GNU inlining, a declaration with 'inline' but not 'extern', forces
// an externally visible definition.
@@ -3289,9 +3292,6 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
- if (Context.getLangOpts().CPlusPlus)
- return false;
-
// C99 6.7.4p6:
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
@@ -3371,6 +3371,8 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
if (!(isInlineSpecified() && getStorageClass() == SC_Extern))
return true;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b69cb5d843..d31b48c122 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -4255,6 +4255,9 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
+ if (S.LangOpts.CPlusPlus && Fn->getStorageClass() != SC_Extern)
+ S.Diag(AL.getLoc(), diag::warn_gnu_inline_cplusplus_without_extern);
+
D->addAttr(::new (S.Context) GNUInlineAttr(S.Context, AL));
}
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index ea6e9d7649..b511ece281 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -52,7 +52,7 @@
// CHECK3-LABEL: define i32 @_Z3barv()
// CHECK3-LABEL: define linkonce_odr i32 @_Z3foov()
// CHECK3-NOT: unreferenced
-// CHECK3-LABEL: define void @_Z10gnu_inlinev()
+// CHECK3-LABEL: define available_externally void @_Z10gnu_inlinev()
// CHECK3-LABEL: define available_externally void @_Z13gnu_ei_inlinev()
// CHECK3-NOT: @_Z5testCv
// CHECK3-LABEL: define linkonce_odr i32 @_Z2eiv()
@@ -85,6 +85,7 @@ __inline void unreferenced1() {}
extern __inline void unreferenced2() {}
__inline __attribute((__gnu_inline__)) void gnu_inline() {}
+void (*P1)() = gnu_inline;
// PR3988
extern __inline __attribute__((gnu_inline)) void gnu_ei_inline() {}
diff --git a/test/SemaCUDA/gnu-inline.cu b/test/SemaCUDA/gnu-inline.cu
index 0ed543326b..e383082f2a 100644
--- a/test/SemaCUDA/gnu-inline.cu
+++ b/test/SemaCUDA/gnu-inline.cu
@@ -7,4 +7,4 @@
// Check that we can handle gnu_inline functions when compiling in CUDA mode.
void foo();
-inline __attribute__((gnu_inline)) void bar() { foo(); }
+extern inline __attribute__((gnu_inline)) void bar() { foo(); }
diff --git a/test/SemaCXX/gnu_inline.cpp b/test/SemaCXX/gnu_inline.cpp
new file mode 100644
index 0000000000..43a4bae48e
--- /dev/null
+++ b/test/SemaCXX/gnu_inline.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+extern inline
+__attribute__((__gnu_inline__))
+void gnu_inline1() {}
+
+inline
+__attribute__((__gnu_inline__)) // expected-warning {{'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10}}
+void gnu_inline2() {}
diff --git a/test/SemaCXX/undefined-inline.cpp b/test/SemaCXX/undefined-inline.cpp
index feb12f4552..21c6b5de79 100644
--- a/test/SemaCXX/undefined-inline.cpp
+++ b/test/SemaCXX/undefined-inline.cpp
@@ -40,20 +40,20 @@ namespace test7 {
}
namespace test8 {
- inline void foo() __attribute__((gnu_inline));
+ inline void foo() __attribute__((gnu_inline)); // expected-warning {{'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10}}
void test() { foo(); }
}
namespace test9 {
void foo();
void test() { foo(); }
- inline void foo() __attribute__((gnu_inline));
+ inline void foo() __attribute__((gnu_inline)); // expected-warning {{'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10}}
}
namespace test10 {
inline void foo();
void test() { foo(); }
- inline void foo() __attribute__((gnu_inline));
+ inline void foo() __attribute__((gnu_inline)); // expected-warning {{'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10}}
}
namespace test11 {