r359259 - Add missing diagnostic for explicit instantiation declarations naming

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 25 18:51:07 PDT 2019


Author: rsmith
Date: Thu Apr 25 18:51:07 2019
New Revision: 359259

URL: http://llvm.org/viewvc/llvm-project?rev=359259&view=rev
Log:
Add missing diagnostic for explicit instantiation declarations naming
internal linkage entities.

Such constructs are ill-formed by [temp.explicit]p13. We make a special
exception to permit an invalid construct used by libc++ in some build
modes: its <valarray> header declares some functions with the
internal_linkage attribute and then (meaninglessly) provides explicit
instantiation declarations for them. Luckily, Clang happens to
effectively ignore the explicit instantiation declaration when
generating code in this case, and this change codifies that behavior.

This reinstates part of r359048, reverted in r359076. (The libc++ issue
triggering the rollback has been addressed.)

Added:
    cfe/trunk/test/SemaCXX/libcxx_valarray_hack.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/drs/dr0xx.cpp
    cfe/trunk/test/SemaCXX/PR10177.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=359259&r1=359258&r2=359259&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Apr 25 18:51:07 2019
@@ -4384,6 +4384,8 @@ def err_explicit_instantiation_of_typede
   "explicit instantiation of typedef %0">;
 def err_explicit_instantiation_storage_class : Error<
   "explicit instantiation cannot have a storage class">;
+def err_explicit_instantiation_internal_linkage : Error<
+  "explicit instantiation declaration of %0 with internal linkage">;
 def err_explicit_instantiation_not_known : Error<
   "explicit instantiation of %0 does not refer to a function template, "
   "variable template, member function, member class, or static data member">;

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=359259&r1=359258&r2=359259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr 25 18:51:07 2019
@@ -8619,6 +8619,29 @@ static bool CheckExplicitInstantiationSc
   return false;
 }
 
+/// Common checks for whether an explicit instantiation of \p D is valid.
+static bool CheckExplicitInstantiation(Sema &S, NamedDecl *D,
+                                       SourceLocation InstLoc,
+                                       bool WasQualifiedName,
+                                       TemplateSpecializationKind TSK) {
+  // C++ [temp.explicit]p13:
+  //   An explicit instantiation declaration shall not name a specialization of
+  //   a template with internal linkage.
+  if (TSK == TSK_ExplicitInstantiationDeclaration &&
+      D->getFormalLinkage() == InternalLinkage) {
+    S.Diag(InstLoc, diag::err_explicit_instantiation_internal_linkage) << D;
+    return true;
+  }
+
+  // C++11 [temp.explicit]p3: [DR 275]
+  //   An explicit instantiation shall appear in an enclosing namespace of its
+  //   template.
+  if (CheckExplicitInstantiationScope(S, D, InstLoc, WasQualifiedName))
+    return true;
+
+  return false;
+}
+
 /// Determine whether the given scope specifier has a template-id in it.
 static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
   if (!SS.isSet())
@@ -8770,13 +8793,8 @@ DeclResult Sema::ActOnExplicitInstantiat
   TemplateSpecializationKind PrevDecl_TSK
     = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
 
-  // C++0x [temp.explicit]p2:
-  //   [...] An explicit instantiation shall appear in an enclosing
-  //   namespace of its template. [...]
-  //
-  // This is C++ DR 275.
-  if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc,
-                                      SS.isSet()))
+  if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
+                                 SS.isSet(), TSK))
     return true;
 
   ClassTemplateSpecializationDecl *Specialization = nullptr;
@@ -8999,12 +9017,7 @@ Sema::ActOnExplicitInstantiation(Scope *
     = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
                            : TSK_ExplicitInstantiationDeclaration;
 
-  // C++0x [temp.explicit]p2:
-  //   [...] An explicit instantiation shall appear in an enclosing
-  //   namespace of its template. [...]
-  //
-  // This is C++ DR 275.
-  CheckExplicitInstantiationScope(*this, Record, NameLoc, true);
+  CheckExplicitInstantiation(*this, Record, NameLoc, true, TSK);
 
   // Verify that it is okay to explicitly instantiate here.
   CXXRecordDecl *PrevDecl
@@ -9235,8 +9248,7 @@ DeclResult Sema::ActOnExplicitInstantiat
            diag::ext_explicit_instantiation_without_qualified_id)
         << Prev << D.getCXXScopeSpec().getRange();
 
-    // Check the scope of this explicit instantiation.
-    CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
+    CheckExplicitInstantiation(*this, Prev, D.getIdentifierLoc(), true, TSK);
 
     // Verify that it is okay to explicitly instantiate here.
     TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
@@ -9411,6 +9423,20 @@ DeclResult Sema::ActOnExplicitInstantiat
       return (Decl*) nullptr;
   }
 
+  // HACK: libc++ has a bug where it attempts to explicitly instantiate the
+  // functions
+  //     valarray<size_t>::valarray(size_t) and
+  //     valarray<size_t>::~valarray()
+  // that it declared to have internal linkage with the internal_linkage
+  // attribute. Ignore the explicit instantiation declaration in this case.
+  if (Specialization->hasAttr<InternalLinkageAttr>() &&
+      TSK == TSK_ExplicitInstantiationDeclaration) {
+    if (auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getDeclContext()))
+      if (RD->getIdentifier() && RD->getIdentifier()->isStr("valarray") &&
+          RD->isInStdNamespace())
+        return (Decl*) nullptr;
+  }
+
   ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes());
 
   // In MSVC mode, dllimported explicit instantiation definitions are treated as
@@ -9444,11 +9470,11 @@ DeclResult Sema::ActOnExplicitInstantiat
          diag::ext_explicit_instantiation_without_qualified_id)
     << Specialization << D.getCXXScopeSpec().getRange();
 
-  CheckExplicitInstantiationScope(*this,
-                   FunTmpl? (NamedDecl *)FunTmpl
-                          : Specialization->getInstantiatedFromMemberFunction(),
-                                  D.getIdentifierLoc(),
-                                  D.getCXXScopeSpec().isSet());
+  CheckExplicitInstantiation(
+      *this,
+      FunTmpl ? (NamedDecl *)FunTmpl
+              : Specialization->getInstantiatedFromMemberFunction(),
+      D.getIdentifierLoc(), D.getCXXScopeSpec().isSet(), TSK);
 
   // FIXME: Create some kind of ExplicitInstantiationDecl here.
   return (Decl*) nullptr;

Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=359259&r1=359258&r2=359259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Thu Apr 25 18:51:07 2019
@@ -869,18 +869,17 @@ namespace dr68 { // dr68: yes
 }
 
 namespace dr69 { // dr69: yes
-  template<typename T> static void f() {}
+  template<typename T> static void f() {} // #dr69-f
   // FIXME: Should we warn here?
   inline void g() { f<int>(); }
-  // FIXME: This should be rejected, per [temp.explicit]p11.
-  extern template void f<char>();
+  extern template void f<char>(); // expected-error {{explicit instantiation declaration of 'f' with internal linkage}}
 #if __cplusplus < 201103L
   // expected-error at -2 {{C++11 extension}}
 #endif
   template<void(*)()> struct Q {};
   Q<&f<int> > q;
 #if __cplusplus < 201103L
-  // expected-error at -2 {{internal linkage}} expected-note at -11 {{here}}
+  // expected-error at -2 {{internal linkage}} expected-note@#dr69-f {{here}}
 #endif
 }
 

Modified: cfe/trunk/test/SemaCXX/PR10177.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR10177.cpp?rev=359259&r1=359258&r2=359259&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/PR10177.cpp (original)
+++ cfe/trunk/test/SemaCXX/PR10177.cpp Thu Apr 25 18:51:07 2019
@@ -57,11 +57,10 @@ namespace N {
 }
 
 #else
-// expected-no-diagnostics
 
 namespace { template<typename> extern int n; }
 template<typename T> int g() { return n<int>; }
-namespace { extern template int n<int>; }
+namespace { extern template int n<int>; } // expected-error {{explicit instantiation declaration of 'n<int>' with internal linkage}}
 
 #endif
 

Added: cfe/trunk/test/SemaCXX/libcxx_valarray_hack.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/libcxx_valarray_hack.cpp?rev=359259&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/libcxx_valarray_hack.cpp (added)
+++ cfe/trunk/test/SemaCXX/libcxx_valarray_hack.cpp Thu Apr 25 18:51:07 2019
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify
+
+// This is a test for a hack in Clang that works around an issue with libc++'s
+// <valarray> implementation. The <valarray> header contains explicit
+// instantiations of functions that it declared with the internal_linkage
+// attribute, which are ill-formed by [temp.explicit]p13 (and meaningless).
+
+#ifdef BE_THE_HEADER
+
+#pragma GCC system_header
+namespace std {
+  using size_t = __SIZE_TYPE__;
+  template<typename T> struct valarray {
+    __attribute__((internal_linkage)) valarray(size_t) {}
+    __attribute__((internal_linkage)) ~valarray() {}
+  };
+
+  extern template valarray<size_t>::valarray(size_t);
+  extern template valarray<size_t>::~valarray();
+}
+
+#else
+
+#define BE_THE_HEADER
+#include "libcxx_valarray_hack.cpp"
+
+template<typename T> struct foo {
+  __attribute__((internal_linkage)) void x() {};
+};
+extern template void foo<int>::x(); // expected-error {{explicit instantiation declaration of 'x' with internal linkage}}
+
+#endif




More information about the cfe-commits mailing list