loladiro updated this revision to Diff 41261.
loladiro added a comment.
Rebased and made the small suggested changes to the test cases.
http://reviews.llvm.org/D13330
Files:
include/clang/AST/ASTContext.h
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/AttributeList.h
lib/AST/ASTContext.cpp
lib/CodeGen/CGVTables.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.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
@@ -2371,6 +2371,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,34 @@
+// RUN: %clang -cc1 -std=c++11 -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>;
+
+// Various examples of incorrect usage
+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>
+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,38 @@
+// RUN: %clang -std=c++11 -emit-llvm -c -S -o - %s | FileCheck %s
+
+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: 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
@@ -7398,20 +7398,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;
}
@@ -7465,14 +7467,7 @@
}
}
- // 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);
}
return Specialization;
@@ -7923,11 +7918,35 @@
return (Decl*) nullptr;
}
+ bool HadDeclaration = Specialization->getTemplateSpecializationKind() ==
+ TSK_ExplicitInstantiationDeclaration;
+ auto *OldUniqueInstantiation =
+ Specialization->getAttr<UniqueInstantiationAttr>();
+ SourceLocation OldUniqueInstantiationLoc;
+ 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);
+ auto *NewUniqueInstantiation =
+ Specialization->getAttr<UniqueInstantiationAttr>();
+ if (NewUniqueInstantiation) {
+ if (TSK == TSK_ExplicitInstantiationDefinition && !HadDeclaration)
+ Diag(NewUniqueInstantiation->getLocation(),
+ diag::err_unique_instantiation_no_declaration);
+ else if (HadDeclaration && !OldUniqueInstantiation)
+ Diag(NewUniqueInstantiation->getLocation(),
+ diag::err_unique_instantiation_not_previous);
+ } else if (OldUniqueInstantiation) {
+ Diag(D.getIdentifierLoc(), diag::err_unique_instantiation_not_previous);
+ Diag(OldUniqueInstantiationLoc, diag::note_previous_explicit_instantiation);
+ }
+
if (Specialization->isDefined()) {
// Let the ASTConsumer know that this function has been explicitly
// instantiated now, and its linkage might have changed.
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4757,6 +4757,32 @@
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);
+ }
+ 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.
@@ -5138,6 +5164,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;
@@ -2382,6 +2407,8 @@
// attributes declared post-definition are currently ignored
checkNewAttributesAfterDef(*this, New, Old);
+ checkUniqueInstantiationAttrs(*this, New, Old);
+
if (!Old->hasAttrs())
return;
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -741,6 +741,10 @@
llvm::Function::InternalLinkage;
case TSK_ExplicitInstantiationDefinition:
+ // If the key function has strong linkage (say due to
+ // UniqueInstantiationAttr), the VTable should too.
+ if (Context.containedInUniqueInstantiation(keyFunction))
+ return llvm::GlobalVariable::ExternalLinkage;
return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::WeakODRLinkage :
llvm::Function::InternalLinkage;
@@ -759,7 +763,10 @@
llvm::GlobalValue::LinkOnceODRLinkage;
llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage =
llvm::GlobalValue::WeakODRLinkage;
- if (RD->hasAttr<DLLExportAttr>()) {
+ if (RD->hasAttr<UniqueInstantiationAttr>() ||
+ Context.containedInUniqueInstantiation(RD)) {
+ 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
@@ -8254,6 +8254,17 @@
return getFunctionType(ResType, ArgTypes, EPI);
}
+bool ASTContext::containedInUniqueInstantiation(const Decl *D) {
+ const RecordDecl *RD;
+ while ((RD = dyn_cast<RecordDecl>(D->getDeclContext()))) {
+ auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
+ if (CTSD && CTSD->hasAttr<UniqueInstantiationAttr>())
+ return true;
+ D = RD;
+ }
+ return false;
+}
+
static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
const FunctionDecl *FD) {
if (!FD->isExternallyVisible())
@@ -8267,6 +8278,14 @@
break;
case TSK_ExplicitInstantiationDefinition:
+ if (FD->hasAttr<UniqueInstantiationAttr>() ||
+ Context.containedInUniqueInstantiation(FD)) {
+ // We return GVA_StrongExternal here, instead of going through the logic
+ // below, because even if the definition is available inline, since the
+ // source specified an explicit template instantiation, we want to make
+ // the symbol available.
+ return GVA_StrongExternal;
+ }
return GVA_StrongODR;
// C++11 [temp.explicit]p10:
@@ -8369,6 +8388,8 @@
: GVA_StrongExternal;
case TSK_ExplicitInstantiationDefinition:
+ if (Context.containedInUniqueInstantiation(VD))
+ return GVA_StrongExternal;
return GVA_StrongODR;
case TSK_ExplicitInstantiationDeclaration:
Index: include/clang/Sema/AttributeList.h
===================================================================
--- include/clang/Sema/AttributeList.h
+++ include/clang/Sema/AttributeList.h
@@ -853,7 +853,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
@@ -2424,7 +2424,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<
@@ -2529,6 +2530,12 @@
"%plural{0:no parameters to index into|"
"1:can only be 1, since there is one parameter|"
":must be between 1 and %2}2">;
+def err_unique_instantiation_wrong_decl : Error<
+ "'unique_instantiation' attribute only applies to an explicit template declaration or instantiation">;
+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">,
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -1719,6 +1719,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
@@ -1489,6 +1489,12 @@
let Documentation = [Undocumented];
}
+def UniqueInstantiation : InheritableAttr {
+ let Spellings = [GNU<"unique_instantiation">];
+ let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>;
+ let Documentation = [UniqueInstantiationDocs];
+}
+
def WeakImport : InheritableAttr {
let Spellings = [GNU<"weak_import">];
let Documentation = [Undocumented];
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -2360,6 +2360,7 @@
/// when it is called.
void AddDeallocation(void (*Callback)(void*), void *Data);
+ static bool containedInUniqueInstantiation(const Decl *D);
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits