r224651 - Don't drop attributes when checking explicit specializations.

Nico Weber nicolasweber at gmx.de
Fri Dec 19 15:52:45 PST 2014


Author: nico
Date: Fri Dec 19 17:52:45 2014
New Revision: 224651

URL: http://llvm.org/viewvc/llvm-project?rev=224651&view=rev
Log:
Don't drop attributes when checking explicit specializations.

Consider a template class with attributes on a method, and an explicit
specialization of that method:

    template <int>
    struct A {
      void foo() final;
    };

    template <>
    void A<0>::foo() {}

In this example, the attribute is `final`, but it might also be an
__attribute__((visibility("foo"))), noreturn, inline, etc. clang's current
behavior is to strip all attributes, which for some attributes is wrong
(the snippet above allows a subclass of A<0> to override the final method, for
example) and for others disagrees with gcc.

So stop dropping attributes. r95845 added this code without a test case, and
r176728 added the code for dropping attributes on parameters (with tests, but
they still pass).

As an additional wrinkle, do drop dllimport and dllexport, since that's how
these two attributes work. (This is covered by existing tests.)

Fixes PR21942.

The approach is by Richard Smith, initial analysis and typing was done by me.

With this, clang also matches GCC and EDG on all attributes Richard tested.

Modified:
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
    cfe/trunk/test/SemaTemplate/function-template-specialization-noreturn.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=224651&r1=224650&r2=224651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Dec 19 17:52:45 2014
@@ -6434,14 +6434,11 @@ Decl *Sema::ActOnStartOfFunctionTemplate
 /// \brief Strips various properties off an implicit instantiation
 /// that has just been explicitly specialized.
 static void StripImplicitInstantiation(NamedDecl *D) {
-  D->dropAttrs();
+  D->dropAttr<DLLImportAttr>();
+  D->dropAttr<DLLExportAttr>();
 
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
     FD->setInlineSpecified(false);
-
-    for (auto I : FD->params())
-      I->dropAttrs();
-  }
 }
 
 /// \brief Compute the diagnostic location for an explicit instantiation

Modified: cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp?rev=224651&r1=224650&r2=224651&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp (original)
+++ cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp Fri Dec 19 17:52:45 2014
@@ -164,3 +164,19 @@ template void Foo(float a);
 // expected-error at +1 0-1 {{exception specification in explicit instantiation does not match instantiated one}}
 template void Foo(double a) noexcept;
 #endif
+
+#if __cplusplus >= 201103L
+namespace PR21942 {
+template <int>
+struct A {
+  virtual void foo() final;
+};
+
+template <>
+void A<0>::foo() {} // expected-note{{overridden virtual function is here}}
+
+struct B : A<0> {
+  virtual void foo() override; // expected-error{{declaration of 'foo' overrides a 'final' function}}
+};
+}
+#endif

Modified: cfe/trunk/test/SemaTemplate/function-template-specialization-noreturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/function-template-specialization-noreturn.cpp?rev=224651&r1=224650&r2=224651&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/function-template-specialization-noreturn.cpp (original)
+++ cfe/trunk/test/SemaTemplate/function-template-specialization-noreturn.cpp Fri Dec 19 17:52:45 2014
@@ -6,3 +6,15 @@
 
 template <int N> void __attribute__((noreturn)) f3() { __builtin_unreachable(); }
 template <> void f3<1>() { } // expected-warning {{function declared 'noreturn' should not return}}
+
+#if __cplusplus >= 201103L
+namespace PR21942 {
+template <int>
+struct A {
+  void foo[[noreturn]]();
+};
+
+template <>
+void A<0>::foo() {} // expected-warning{{function declared 'noreturn' should not return}}
+}
+#endif





More information about the cfe-commits mailing list