loladiro updated this revision to Diff 76256.
loladiro added a comment.

Fix for the corner case I found and add it as a test.


Repository:
  rL LLVM

https://reviews.llvm.org/D13330

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/AttributeList.h
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/CodeGen/CGVTables.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplate.cpp
  test/CodeGenCXX/unique-instantiation.cpp
  test/SemaCXX/unique-instantiations.cpp
  utils/TableGen/ClangAttrEmitter.cpp

Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -2662,6 +2662,8 @@
     case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter";
     case Func | ObjCMethod: return "ExpectedFunctionOrMethod";
     case Func | Var: return "ExpectedVariableOrFunction";
+    case Func | Class:
+      return "ExpectedFunctionOrClass";
 
     // If not compiling for C++, the class portion does not apply.
     case Func | Var | Class:
Index: test/SemaCXX/unique-instantiations.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/unique-instantiations.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s
+
+// Correct usage
+template <typename T>
+struct foo {};
+extern template struct __attribute__((unique_instantiation)) foo<int>;
+template struct __attribute__((unique_instantiation)) foo<int>;
+
+template <typename T>
+T pi = T(3.1415926535897932385);
+extern template __attribute__((unique_instantiation)) float pi<float>;
+template __attribute__((unique_instantiation)) float pi<float>;
+
+// Usages on non-templates
+float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}}
+struct __attribute__((unique_instantiation)) bar {};                                // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}}
+void __attribute__((unique_instantiation)) func() {}                                // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}}
+
+// Usages that violate one of the conditions required conditions
+template <typename T>
+struct foo1 {};
+template struct __attribute__((unique_instantiation)) foo1<int>; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}}
+
+template <typename T>
+T pi1 = T(3.1415926535897932385);
+template __attribute__((unique_instantiation)) float pi1<float>; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}}
+
+template <typename T>
+struct foo2 {};
+extern template struct foo2<int>;                                // expected-note{{previous explicit instantiation is here}}
+template struct __attribute__((unique_instantiation)) foo2<int>; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}}
+
+template <typename T>
+struct foo3 {};
+extern template struct __attribute__((unique_instantiation)) foo3<int>; // expected-note{{previous explicit instantiation is here}}
+extern template struct foo3<int>;                                       // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}}
+
+template <typename T>
+struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}}
+
+template <typename T>
+struct foo5 {};
+extern template struct __attribute__((unique_instantiation)) foo5<int>; // expected-note{{previous explicit instantiation is here}}
+template struct foo5<int>;                                              // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}}
+
+template <typename T>
+struct foo6 {};
+extern template struct __attribute__((unique_instantiation(16))) foo6<int>; // expected-error{{'unique_instantiation' attribute takes no arguments}}
+
+template <typename T>
+struct static_separate_template {
+    typedef T element;
+    static T *a_static_field;
+};
+extern template struct __attribute__((unique_instantiation)) static_separate_template<int>;
+template struct __attribute__((unique_instantiation)) static_separate_template<int>;
+extern template struct __attribute__((unique_instantiation)) static_separate_template<char>; // expected-note{{previous explicit instantiation is here}}
+template struct __attribute__((unique_instantiation)) static_separate_template<char>;
+
+template <typename T> typename static_separate_template<T>::element *static_separate_template<T>::a_static_field = nullptr;
+template __attribute__((unique_instantiation)) int * static_separate_template<int>::a_static_field;
+template char * static_separate_template<char>::a_static_field; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}}
Index: test/CodeGenCXX/unique-instantiation.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/unique-instantiation.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s
+
+// CHECK: @_Z2piIfE = global float
+// CHECK-NOT: @_Z2piIfE = weak_odr global float
+template <typename T>
+T pi = T(3.1415926535897932385);
+extern template __attribute__((unique_instantiation)) float pi<float>;
+template __attribute__((unique_instantiation)) float pi<float>;
+
+template <typename T>
+struct foo {
+  T x;
+  T getX() { return x; }
+  struct bar {
+    T y;
+    bar(T y) : y(y) {}
+  };
+};
+template <typename T>
+T bar();
+
+// CHECK: _ZZ12functemplateIiEDaT_E11innerStatic = global i32 0, align 4
+// CHECK: @_ZTVZ12functemplateIiEDaT_E5inner = unnamed_addr
+// CHECK: @_ZTSZ12functemplateIiEDaT_E5inner = constant
+// CHECK: @_ZTIZ12functemplateIiEDaT_E5inner = constant
+// CHECK-NOT: @_ZZ12functemplateIiEDaT_E11innerStatic = linkonce_odr global
+// CHECK-NOT: @_ZTVZ12functemplateIiEDaT_E5inner = linkoce_odr unnamed_addr
+// CHECK-NOT: @_ZTSZ12functemplateIiEDaT_E5inner = linkoce_odr unnamed_addr
+// CHECK-NOT: @_ZTIZ12functemplateIiEDaT_E5inner = linkoce_odr unnamed_addr
+template <typename T>
+auto functemplate(T x) {
+  static T innerStatic = x;
+  class inner {
+    T y;
+
+  public:
+    virtual ~inner() {}
+    inner(T y) : y(y) {}
+    T getY() { return y; }
+  };
+  return inner{x}.getY();
+}
+
+// CHECK: define i32 @_Z12functemplateIiEDaT_
+// CHECK: define i32 @_ZZ12functemplateIiEDaT_EN5inner4getYEv
+// CHECK-NOT: define weak_odr i32 @_Z12functemplateIiEDaT_
+// CHECK-NOT: define linkonce_odr i32 @_ZZ12functemplateIiEDaT_EN5inner4getYEv
+extern template auto __attribute__((unique_instantiation)) functemplate<int>(int);
+template auto __attribute__((unique_instantiation)) functemplate<int>(int);
+
+// CHECK: define i32 @_ZN3fooIiE4getXEv
+// CHECK: define void @_ZN3fooIiE3barC2Ei
+// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv
+// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei
+extern template struct __attribute__((unique_instantiation)) foo<int>;
+template struct __attribute__((unique_instantiation)) foo<int>;
+
+extern template __attribute__((unique_instantiation)) int bar<int>();
+extern template __attribute__((unique_instantiation)) short bar<short>();
+
+template <typename T>
+T bar() {
+  return (T)0;
+}
+
+// CHECK: define i32 @_Z3barIiET_v()
+// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v()
+template __attribute__((unique_instantiation)) int bar<int>();
+
+// CHECK: declare signext i16 @_Z3barIsET_v
+int footest() {
+  auto var = foo<int>{5};
+  auto var2 = foo<int>::bar{5};
+  auto x = bar<int>();
+  auto z = bar<short>();
+  return var.getX();
+}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -7622,20 +7622,22 @@
   Specialization->setExternLoc(ExternLoc);
   Specialization->setTemplateKeywordLoc(TemplateLoc);
   Specialization->setBraceRange(SourceRange());
+  Specialization->setTemplateSpecializationKind(TSK);
 
   if (Attr)
     ProcessDeclAttributeList(S, Specialization, Attr);
 
+  if (PrevDecl)
+    mergeDeclAttributes(Specialization, PrevDecl);
+
   // Add the explicit instantiation into its lexical context. However,
   // since explicit instantiations are never found by name lookup, we
   // just put it into the declaration context directly.
   Specialization->setLexicalDeclContext(CurContext);
   CurContext->addDecl(Specialization);
 
   // Syntax is now OK, so return if it has no other effect on semantics.
   if (HasNoEffect) {
-    // Set the template specialization kind.
-    Specialization->setTemplateSpecializationKind(TSK);
     return Specialization;
   }
 
@@ -7695,14 +7697,8 @@
       }
     }
 
-    // Set the template specialization kind. Make sure it is set before
-    // instantiating the members which will trigger ASTConsumer callbacks.
-    Specialization->setTemplateSpecializationKind(TSK);
     InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
-  } else {
-
-    // Set the template specialization kind.
-    Specialization->setTemplateSpecializationKind(TSK);
+    propagateUniqueInstantiation(Def);
   }
 
   return Specialization;
@@ -7832,6 +7828,26 @@
   return TagD;
 }
 
+static void
+DiagnoseUniqueInstantiation(Sema &S, Declarator &D,
+                            TemplateSpecializationKind TSK, bool HadDeclaration,
+                            UniqueInstantiationAttr *NewUniqueInstantiation,
+                            UniqueInstantiationAttr *OldUniqueInstantiation,
+                            clang::SourceLocation OldUniqueInstantiationLoc) {
+  if (NewUniqueInstantiation) {
+    if (TSK == TSK_ExplicitInstantiationDefinition && !HadDeclaration)
+      S.Diag(NewUniqueInstantiation->getLocation(),
+             diag::err_unique_instantiation_no_declaration);
+    else if (HadDeclaration && !OldUniqueInstantiation)
+      S.Diag(NewUniqueInstantiation->getLocation(),
+             diag::err_unique_instantiation_not_previous);
+  } else if (OldUniqueInstantiation) {
+    S.Diag(D.getIdentifierLoc(), diag::err_unique_instantiation_not_previous);
+    S.Diag(OldUniqueInstantiationLoc,
+           diag::note_previous_explicit_instantiation);
+  }
+}
+
 DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
                                             SourceLocation ExternLoc,
                                             SourceLocation TemplateLoc,
@@ -7915,6 +7931,11 @@
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName);
   LookupParsedName(Previous, S, &D.getCXXScopeSpec());
 
+  // For diagnosing incorrect uses of unique_instantiation
+  UniqueInstantiationAttr *OldUniqueInstantiation = nullptr;
+  SourceLocation OldUniqueInstantiationLoc;
+  bool HadDeclaration;
+
   if (!R->isFunctionType()) {
     // C++ [temp.explicit]p1:
     //   A [...] static data member of a class template can be explicitly
@@ -7996,6 +8017,14 @@
       // Ignore access control bits, we don't need them for redeclaration
       // checking.
       Prev = cast<VarDecl>(Res.get());
+
+    }
+    HadDeclaration = Prev->getTemplateSpecializationKind() ==
+                     TSK_ExplicitInstantiationDeclaration;
+    OldUniqueInstantiation = Prev->getAttr<UniqueInstantiationAttr>();
+    if (OldUniqueInstantiation) {
+      OldUniqueInstantiationLoc = OldUniqueInstantiation->getLocation();
+      Prev->dropAttr<UniqueInstantiationAttr>();
     }
 
     // C++0x [temp.explicit]p2:
@@ -8028,11 +8057,13 @@
       // Instantiate static data member or variable template.
 
       Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
-      if (PrevTemplate) {
-        // Merge attributes.
-        if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList())
-          ProcessDeclAttributeList(S, Prev, Attr);
-      }
+      // Merge attributes.
+      if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList())
+        ProcessDeclAttributeList(S, Prev, Attr);
+      DiagnoseUniqueInstantiation(*this, D, TSK, HadDeclaration,
+                                  Prev->getAttr<UniqueInstantiationAttr>(),
+                                  OldUniqueInstantiation,
+                                  OldUniqueInstantiationLoc);
       if (TSK == TSK_ExplicitInstantiationDefinition)
         InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
     }
@@ -8171,11 +8202,24 @@
       return (Decl*) nullptr;
   }
 
+  HadDeclaration = Specialization->getTemplateSpecializationKind() ==
+                   TSK_ExplicitInstantiationDeclaration;
+  OldUniqueInstantiation = Specialization->getAttr<UniqueInstantiationAttr>();
+  if (OldUniqueInstantiation) {
+    OldUniqueInstantiationLoc = OldUniqueInstantiation->getLocation();
+    Specialization->dropAttr<UniqueInstantiationAttr>();
+  }
+
   Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
   AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
   if (Attr)
     ProcessDeclAttributeList(S, Specialization, Attr);
 
+  DiagnoseUniqueInstantiation(
+      *this, D, TSK, HadDeclaration,
+      Specialization->getAttr<UniqueInstantiationAttr>(),
+      OldUniqueInstantiation, OldUniqueInstantiationLoc);
+
   if (Specialization->isDefined()) {
     // Let the ASTConsumer know that this function has been explicitly
     // instantiated now, and its linkage might have changed.
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -5663,6 +5663,54 @@
   }
 }
 
+/// \brief Check if the new class needs a unique instantiation attribute
+/// based on whether its containing function or class has it
+void Sema::checkClassLevelUniqueInstantiation(CXXRecordDecl *Record) {
+  Decl *D = Record;
+  if (!D || D->hasAttr<UniqueInstantiationAttr>())
+    return;
+  while (DeclContext *DC = D ? D->getDeclContext() : nullptr) {
+    if (isa<FunctionDecl>(DC) || isa<CXXRecordDecl>(DC)) {
+      if (InheritableAttr *Attr =
+              cast<Decl>(DC)->getAttr<UniqueInstantiationAttr>()) {
+        auto *NewAttr = cast<InheritableAttr>(Attr->clone(getASTContext()));
+        NewAttr->setInherited(true);
+        Record->addAttr(NewAttr);
+        propagateUniqueInstantiation(Record);
+      }
+      return;
+    }
+    D = dyn_cast<Decl>(DC);
+  }
+}
+
+void Sema::propagateUniqueInstantiation(CXXRecordDecl *Class) {
+  InheritableAttr *Attr = Class->getAttr<UniqueInstantiationAttr>();
+  if (!Attr)
+    return;
+  for (Decl *Member : Class->decls()) {
+    VarDecl *VD = dyn_cast<VarDecl>(Member);
+    CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
+    CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member);
+
+    if (!VD && !MD && !RD)
+      continue;
+
+    if (MD) {
+      // Don't process deleted methods.
+      if (MD->isDeleted())
+        continue;
+    }
+
+    if (!cast<NamedDecl>(Member)->isExternallyVisible())
+      continue;
+
+    auto *NewAttr = cast<InheritableAttr>(Attr->clone(getASTContext()));
+    NewAttr->setInherited(true);
+    Member->addAttr(NewAttr);
+  }
+}
+
 /// \brief Perform semantic checks on a class definition that has been
 /// completing, introducing implicitly-declared members, checking for
 /// abstract types, etc.
@@ -5807,6 +5855,8 @@
   }
 
   checkClassLevelDLLAttribute(Record);
+
+  checkClassLevelUniqueInstantiation(Record);
 }
 
 /// Look up the special member function that would be called by a special
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -5385,6 +5385,38 @@
         << Attr.getName() << "2.0";
 }
 
+static void handleUniqueInstantiation(Sema &S, Decl *D,
+                                      const AttributeList &Attr) {
+  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+    // If this is an explicit instantiation definition. Check that it was
+    // preceeded by an ExplicitInstantiationDeclaration. Note, this
+    // requirement encourages a programming style that uses unique explicit
+    // instantiation declarations (typically in a header) to suppress
+    // implicit instantiations of a template or its members, so that the
+    // unique explicit instantiation definition of that template or its members
+    // is unique.
+    if (CTSD->getSpecializationKind() == TSK_ExplicitInstantiationDefinition) {
+      if (!CTSD->getPreviousDecl())
+        S.Diag(Attr.getLoc(), diag::err_unique_instantiation_no_declaration);
+    }
+    return handleSimpleAttribute<UniqueInstantiationAttr>(S, D, Attr);
+  } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (FD->getTemplateSpecializationKind() ==
+            TSK_ExplicitInstantiationDefinition ||
+        FD->getTemplateSpecializationKind() ==
+            TSK_ExplicitInstantiationDeclaration)
+      return handleSimpleAttribute<UniqueInstantiationAttr>(S, D, Attr);
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    if (VD->getTemplateSpecializationKind() ==
+            TSK_ExplicitInstantiationDefinition ||
+        VD->getTemplateSpecializationKind() ==
+            TSK_ExplicitInstantiationDeclaration)
+      return handleSimpleAttribute<UniqueInstantiationAttr>(S, D, Attr);
+  }
+  S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedExplicitInstantiation;
+}
+
 /// Handles semantic checking for features that are common to all attributes,
 /// such as checking whether a parameter was properly specified, or the correct
 /// number of arguments were passed, etc.
@@ -5812,6 +5844,9 @@
   case AttributeList::AT_Weak:
     handleSimpleAttribute<WeakAttr>(S, D, Attr);
     break;
+  case AttributeList::AT_UniqueInstantiation:
+    handleUniqueInstantiation(S, D, Attr);
+    break;
   case AttributeList::AT_WeakRef:
     handleWeakRefAttr(S, D, Attr);
     break;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2249,6 +2249,31 @@
   return AnyAdded;
 }
 
+static void checkUniqueInstantiationAttrs(Sema &S, const Decl *New,
+                                          const Decl *Old) {
+  Attr *NewAttr = New->getAttr<UniqueInstantiationAttr>();
+  Attr *OldAttr = Old->getAttr<UniqueInstantiationAttr>();
+
+  // Check that any previous definitions also had this attribute set.
+  if (Old->hasAttr<UniqueInstantiationAttr>() == (NewAttr != nullptr))
+    return;
+    
+  // We may have to allow this if the new definition is not a template
+  // declaration/definition (e.g. for an out-of-line template definition of
+  // a static variable).
+  if (OldAttr) {
+    const VarDecl *NewVD = dyn_cast<const VarDecl>(New);  
+    if (NewVD && NewVD->getTemplateSpecializationKind() == clang::TSK_Undeclared) {
+      return;
+    }
+}
+  
+
+  SourceLocation NewLoc = NewAttr ? NewAttr->getLocation() : New->getLocStart();
+  S.Diag(NewLoc, diag::err_unique_instantiation_not_previous);
+  S.Diag(Old->getLocStart(), diag::note_previous_explicit_instantiation);
+}
+
 static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
                                const InheritableAttr *Attr,
                                Sema::AvailabilityMergeKind AMK) {
@@ -2367,6 +2392,18 @@
   if (!New->hasAttrs())
     return;
 
+  // Explicit template instantiations need special handling because in certain
+  // ABIs explicit template definitions may add attributes over explicit
+  // template declarations. In clang getDefinition() will get the
+  // ClassTemplateSpecializationDecl associated with the class template
+  // declaration, so we'd give incorrect warnings here.
+  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(New)) {
+    TemplateSpecializationKind Kind = CTSD->getSpecializationKind();
+    if (Kind == TSK_ExplicitInstantiationDeclaration ||
+        Kind == TSK_ExplicitInstantiationDefinition)
+      return;
+  }
+
   const Decl *Def = getDefinition(Old);
   if (!Def || Def == New)
     return;
@@ -2493,6 +2530,8 @@
     }
   }
 
+  checkUniqueInstantiationAttrs(*this, New, Old);
+
   if (!Old->hasAttrs())
     return;
 
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -718,6 +718,9 @@
     if (keyFunction->hasBody(def))
       keyFunction = cast<CXXMethodDecl>(def);
 
+    if (keyFunction->hasAttr<UniqueInstantiationAttr>())
+      return llvm::GlobalValue::ExternalLinkage;
+
     switch (keyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
       case TSK_ExplicitSpecialization:
@@ -735,6 +738,8 @@
         return llvm::GlobalVariable::ExternalLinkage;
 
       case TSK_ImplicitInstantiation:
+        // If the key function has strong linkage (say due to
+        // UniqueInstantiationAttr), the VTable should too.
         return !Context.getLangOpts().AppleKext ?
                  llvm::GlobalVariable::LinkOnceODRLinkage :
                  llvm::Function::InternalLinkage;
@@ -758,7 +763,10 @@
       llvm::GlobalValue::LinkOnceODRLinkage;
   llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage =
       llvm::GlobalValue::WeakODRLinkage;
-  if (RD->hasAttr<DLLExportAttr>()) {
+  if (RD->hasAttr<UniqueInstantiationAttr>()) {
+    DiscardableODRLinkage = llvm::GlobalVariable::ExternalLinkage;
+    NonDiscardableODRLinkage = llvm::GlobalVariable::ExternalLinkage;
+  } else if (RD->hasAttr<DLLExportAttr>()) {
     // Cannot discard exported vtables.
     DiscardableODRLinkage = NonDiscardableODRLinkage;
   } else if (RD->hasAttr<DLLImportAttr>()) {
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -8736,6 +8736,8 @@
     break;
 
   case TSK_ExplicitInstantiationDefinition:
+    if (FD->hasAttr<UniqueInstantiationAttr>())
+      return GVA_StrongExternal;
     return GVA_StrongODR;
 
   // C++11 [temp.explicit]p10:
@@ -8752,6 +8754,14 @@
     break;
   }
 
+  // It can happen that functions have a unique_instantiation attribute, but
+  // not have TSK_ExplicitInstantiation set (e.g. because they are member functions of a local
+  // class) of a unique_instantiation templated functions. However, that
+  // should only be possible if what we're looking at is a definition (as
+  // opposed to a declaration), so treat it as such.
+  if (FD->hasAttr<UniqueInstantiationAttr>())
+    return GVA_StrongExternal;
+
   if (!FD->isInlined())
     return External;
 
@@ -8776,7 +8786,7 @@
   if (FD->isMSExternInline())
     return GVA_StrongODR;
 
-  return GVA_DiscardableODR;
+  return  GVA_DiscardableODR;
 }
 
 static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context,
@@ -8861,6 +8871,8 @@
                : StrongLinkage;
 
   case TSK_ExplicitInstantiationDefinition:
+    if (VD->hasAttr<UniqueInstantiationAttr>())
+      return GVA_StrongExternal;
     return GVA_StrongODR;
 
   case TSK_ExplicitInstantiationDeclaration:
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5504,6 +5504,9 @@
       ClassTemplateSpecializationDecl *BaseTemplateSpec,
       SourceLocation BaseLoc);
 
+  void checkClassLevelUniqueInstantiation(CXXRecordDecl *Record);
+  void propagateUniqueInstantiation(CXXRecordDecl *Decl);
+
   void CheckCompletedCXXClass(CXXRecordDecl *Record);
   void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
                                          Decl *TagDecl,
Index: include/clang/Sema/AttributeList.h
===================================================================
--- include/clang/Sema/AttributeList.h
+++ include/clang/Sema/AttributeList.h
@@ -924,7 +924,9 @@
   ExpectedVariableEnumFieldOrTypedef,
   ExpectedFunctionMethodEnumOrClass,
   ExpectedStructClassVariableFunctionOrInlineNamespace,
-  ExpectedForMaybeUnused
+  ExpectedForMaybeUnused,
+  ExpectedExplicitInstantiation,
+  ExpectedFunctionOrClass
 };
 
 }  // end namespace clang
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2622,7 +2622,9 @@
   "|variables, enums, fields and typedefs"
   "|functions, methods, enums, and classes"
   "|structs, classes, variables, functions, and inline namespaces"
-  "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">,
+  "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members"
+  "|explicit template declarations or definitions"
+  "|functions and classes}1">,
   InGroup<IgnoredAttributes>;
 def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
 def warn_type_attribute_wrong_type : Warning<
@@ -2739,8 +2741,14 @@
   "%plural{0:no parameters to index into|"
   "1:can only be 1, since there is one parameter|"
   ":must be between 1 and %2}2">;
-
-// Thread Safety Analysis   
+def err_unique_instantiation_no_declaration : Error<
+  "'unique_instantiation' attribute on an explicit instantiation requires"
+  " a previous explicit instantiation declaration">;
+def err_unique_instantiation_not_previous : Error<
+  "'unique_instantiation' attribute must be specified for all declarations and"
+  " definitions of this explicit template instantiation">;
+
+// Thread Safety Analysis
 def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">,
   InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_unlock_kind_mismatch : Warning<
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -2300,7 +2300,40 @@
         return callee(); // This call is tail-call optimized.
       }
     };
+  }];
+}
+
+def UniqueInstantiationDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``unique_instantiation`` attribute may only be applied to explicit template
+declarations and definitions, i.e. expressions of the form:
+
+  .. code-block:: c++
+
+    // Explicit template declaration (usually found in a .h file)
+    extern template struct __attribute__((unique_instantiation)) my_template<int>;
+
+    // Explicit template definition (in exactly **ONE** .cpp file)
+    template struct __attribute__((unique_instantiation)) my_template<int>;
+
+
+When the unique_instantiation attribute is specified on an explicit template
+instantiation, the compiler is given license to emit strong symbols for
+this specific explicit template instantiation.
+
+If the attribute is present on one such definition or declaration for a given
+entity, it must be present on all.
+
+Note that to ensure correct execution the user **MUST** make certain that no
+other translation unit has an implicit instantiation of the same entity. In
+particular this means that any usage of the entity has to be preceeded by an
+appropriate explicit template declaration or definition.
 
+It is thus recommended that explicit template declarations are placed in headers
+to suppress any potential implicit instantiation of the entity. In order to
+encourage this programming style, any explicit template definition with this
+attribute **MUST** be preceeded by an appropriate declaration.
   }];
 }
 
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1329,7 +1329,7 @@
   let Documentation = [OverloadableDocs];
 }
 
-def Override : InheritableAttr { 
+def Override : InheritableAttr {
   let Spellings = [Keyword<"override">];
   let SemaHandler = 0;
   let Documentation = [Undocumented];
@@ -1406,7 +1406,7 @@
 
 def WorkGroupSizeHint :  InheritableAttr {
   let Spellings = [GNU<"work_group_size_hint">];
-  let Args = [UnsignedArgument<"XDim">, 
+  let Args = [UnsignedArgument<"XDim">,
               UnsignedArgument<"YDim">,
               UnsignedArgument<"ZDim">];
   let Subjects = SubjectList<[Function], ErrorDiag>;
@@ -1665,6 +1665,12 @@
   let Documentation = [Undocumented];
 }
 
+def UniqueInstantiation : InheritableAttr {
+  let Spellings = [GNU<"unique_instantiation">];
+  let Subjects = SubjectList<[Var, Function, CXXRecord], ErrorDiag>;
+  let Documentation = [UniqueInstantiationDocs];
+}
+
 def WeakImport : InheritableAttr {
   let Spellings = [GNU<"weak_import">];
   let Documentation = [Undocumented];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to