Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1458,6 +1458,12 @@ let Documentation = [Undocumented]; } +def UniqueInstantiation : InheritableAttr { + let Spellings = [GCC<"unique_instantiation">]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [Undocumented]; +} + def WeakImport : InheritableAttr { let Spellings = [GNU<"weak_import">]; let Documentation = [Undocumented]; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2440,6 +2440,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 on something that is not a explicit template declaration or instantiation.">; +def err_unique_instantiation_no_declaration : Error< + "A unique_instantiation attribute on an explicit template instantiation requires a previous declaration.">; +def err_unique_instantiation_not_previous : Error< + "The unique_instantiation must be specified on all declarations and definitions of a particular explicit template instantiation.">; // Thread Safety Analysis def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">, Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8233,6 +8233,7 @@ return GVA_Internal; GVALinkage External = GVA_StrongExternal; + const ClassTemplateSpecializationDecl *CTSD; switch (FD->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: @@ -8240,7 +8241,15 @@ break; case TSK_ExplicitInstantiationDefinition: - return GVA_StrongODR; + CTSD = dyn_cast(FD->getDeclContext()); + if (!CTSD || !CTSD->hasAttr()) + return GVA_StrongODR; + else { + // 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; + } // C++11 [temp.explicit]p10: // [ Note: The intent is that an inline function that is the subject of @@ -8330,6 +8339,7 @@ if (Context.isMSStaticDataMemberInlineDefinition(VD)) return GVA_DiscardableODR; + const ClassTemplateSpecializationDecl *CTSD; switch (VD->getTemplateSpecializationKind()) { case TSK_Undeclared: return GVA_StrongExternal; @@ -8340,7 +8350,11 @@ : GVA_StrongExternal; case TSK_ExplicitInstantiationDefinition: - return GVA_StrongODR; + CTSD = dyn_cast(VD->getDeclContext()); + if (!CTSD || !CTSD->hasAttr()) + return GVA_StrongODR; + else + return GVA_StrongExternal; case TSK_ExplicitInstantiationDeclaration: return GVA_AvailableExternally; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4529,6 +4529,40 @@ Attr.getAttributeSpellingListIndex())); } + +static void handleUniqueInstantiation(Sema &S, Decl *D, + const AttributeList &Attr) { + ClassTemplateSpecializationDecl *CTSD; + if ((CTSD = dyn_cast(D))) { + // If this is an explicit instantiation definition. Check that it was preceeded + // by an ExplicitInstantiationDeclaration. + if (CTSD->getSpecializationKind() == TSK_ExplicitInstantiationDefinition) { + if (!CTSD->getPreviousDecl()) + S.Diag(Attr.getLoc(),diag::err_unique_instantiation_no_declaration); + } + // Now check that any previous definitions also had this attribute set. This + // implicitly checks that all declarations have this attribute set, since we will + // have performed the same check on the previous declaration here. + CXXRecordDecl *Previous = CTSD->getPreviousDecl(); + if (Previous) { + if (!isa(Previous)) { + // - ClassTemplateSpecializationDecl 0xbad <- We want this + // - UniqueInstantiationAttr + // - CXXRecordDecl 0xbeef prev 0xbad <- We have this + Previous = Previous->getPreviousDecl(); + } + assert(isa(Previous)); + if (!Previous->hasAttr()) { + S.Diag(Attr.getLoc(),diag::err_unique_instantiation_not_previous); + S.Diag(Previous->getLocStart(),diag::note_previous_explicit_instantiation); + } + } + handleSimpleAttribute(S,D,Attr); + } else { + S.Diag(Attr.getLoc(),diag::err_unique_instantiation_wrong_decl); + } +} + /// 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. @@ -4904,6 +4938,9 @@ case AttributeList::AT_Weak: handleSimpleAttribute(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/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7321,10 +7321,17 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl && PrevDecl->hasAttr() && + !Specialization->hasAttr()) { + Diag(Specialization->getLocStart(),diag::err_unique_instantiation_not_previous); + Diag(PrevDecl->getLocStart(),diag::note_previous_explicit_instantiation); + } + // 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. @@ -7333,8 +7340,6 @@ // 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; } @@ -7388,14 +7393,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; Index: test/CodeGenCXX/unique-instantiation.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + +template < typename T > struct foo { + T x; + T getX() { return x; } +}; +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +int footest() { + auto var = foo{5}; + return var.getX(); +} Index: test/SemaCXX/unique-instantiations.cpp =================================================================== --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,22 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template < typename T > struct foo1 { }; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template < typename T > struct foo2 { }; +extern template struct foo2; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo3 { }; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified on all declarations}} + +template < typename T > struct __attribute__((unique_instantiation)) foo4 { }; // expected-error{{not a explicit template declaration}} + +template < typename T > struct foo5 { }; +extern template struct foo5; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo5; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo6 { }; +extern template struct __attribute__((unique_instantiation)) foo6; // expected-note{{previous explicit instantiation is here}} +template struct foo6; // expected-error{{must be specified on all declarations}}