loladiro updated this revision to Diff 43218.
loladiro added a comment.
Rebased
http://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
@@ -2369,6 +2369,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,48 @@
+// 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}}
Index: test/CodeGenCXX/unique-instantiation.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/unique-instantiation.cpp
@@ -0,0 +1,74 @@
+// 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>();
+
+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>();
+
+int footest() {
+ auto var = foo<int>{5};
+ auto var2 = foo<int>::bar{5};
+ auto x = bar<int>();
+ return var.getX();
+}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -7400,20 +7400,22 @@
Specialization->setExternLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
Specialization->setRBraceLoc(SourceLocation());
+ 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;
}
@@ -7467,14 +7469,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;
@@ -7604,6 +7600,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,
@@ -7678,6 +7694,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
@@ -7750,6 +7771,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:
@@ -7782,10 +7811,14 @@
// Instantiate static data member or variable template.
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
+ // Merge attributes.
+ if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList())
+ ProcessDeclAttributeList(S, Prev, Attr);
if (PrevTemplate) {
- // 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);
@@ -7925,11 +7958,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
@@ -4904,6 +4904,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.
@@ -5043,6 +5091,8 @@
DeclareInheritingConstructors(Record);
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
@@ -4865,6 +4865,38 @@
D->addAttr(Internal);
}
+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.
@@ -5249,6 +5281,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
@@ -2188,6 +2188,19 @@
return AnyAdded;
}
+static void checkUniqueInstantiationAttrs(Sema &S, const Decl *New,
+ const Decl *Old) {
+ Attr *NewAttr = New->getAttr<UniqueInstantiationAttr>();
+
+ // Check that any previous definitions also had this attribute set.
+ if (Old->hasAttr<UniqueInstantiationAttr>() == (NewAttr != nullptr))
+ 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) {
@@ -2289,6 +2302,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;
@@ -2397,6 +2422,8 @@
}
}
+ checkUniqueInstantiationAttrs(*this, New, Old);
+
if (!Old->hasAttrs())
return;
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -736,7 +736,10 @@
const FunctionDecl *def = nullptr;
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:
@@ -750,19 +753,21 @@
return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::LinkOnceODRLinkage :
llvm::Function::InternalLinkage;
-
+
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;
case TSK_ExplicitInstantiationDefinition:
return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::WeakODRLinkage :
llvm::Function::InternalLinkage;
-
+
case TSK_ExplicitInstantiationDeclaration:
llvm_unreachable("Should not have been asked to emit this");
}
@@ -777,7 +782,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
@@ -8259,6 +8259,12 @@
if (!FD->isExternallyVisible())
return GVA_Internal;
+ // If the attribute is present, this translation unit is
+ // responsible for emitting a unique instantiation of this
+ // function regardless of any of the normal considerations
+ if (FD->hasAttr<UniqueInstantiationAttr>())
+ return GVA_StrongExternal;
+
GVALinkage External = GVA_StrongExternal;
switch (FD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
@@ -8333,6 +8339,9 @@
if (!VD->isExternallyVisible())
return GVA_Internal;
+ if (VD->hasAttr<UniqueInstantiationAttr>())
+ return GVA_StrongExternal;
+
if (VD->isStaticLocal()) {
GVALinkage StaticLocalLinkage = GVA_DiscardableODR;
const DeclContext *LexicalContext = VD->getParentFunctionOrMethod();
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5291,6 +5291,8 @@
CXXRecordDecl *Class, Attr *ClassAttr,
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
@@ -855,7 +855,9 @@
ExpectedStructOrTypedef,
ExpectedObjectiveCInterfaceOrProtocol,
ExpectedKernelFunction,
- ExpectedFunctionWithProtoType
+ ExpectedFunctionWithProtoType,
+ ExpectedExplicitInstantiation,
+ ExpectedFunctionOrClass
};
} // end namespace clang
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2433,7 +2433,8 @@
"Objective-C instance methods|init methods of interface or class extension declarations|"
"variables, functions and classes|Objective-C protocols|"
"functions and global variables|structs, unions, and typedefs|structs and typedefs|"
- "interface or protocol declarations|kernel functions|non-K&R-style functions}1">,
+ "interface or protocol declarations|kernel functions|non-K&R-style functions|"
+ "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<
@@ -2538,8 +2539,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
@@ -1856,6 +1856,39 @@
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
@@ -1220,7 +1220,7 @@
let Documentation = [OverloadableDocs];
}
-def Override : InheritableAttr {
+def Override : InheritableAttr {
let Spellings = [Keyword<"override">];
let SemaHandler = 0;
let Documentation = [Undocumented];
@@ -1288,7 +1288,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>;
@@ -1514,6 +1514,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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits