loladiro updated this revision to Diff 42132. loladiro added a comment. Address David's concern about inner classes. David also suggested on IRC to propagate the unique instantiation attribute down rather than walking the context chain to check for the attribute. I'll try that out, but wanted to put up a known-good version with all fixed first.
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 @@ -2373,6 +2373,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,46 @@ +// 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,69 @@ +// 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: @_ZTVZ12functemplateIiEDaT_E5inner = unnamed_addr +// CHECK: @_ZTSZ12functemplateIiEDaT_E5inner = constant +// CHECK: @_ZTIZ12functemplateIiEDaT_E5inner = constant +// 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 ) { + 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 __attribute__((unique_instantiation)) auto functemplate<int>(int); +template __attribute__((unique_instantiation)) auto 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 @@ -86,14 +86,14 @@ return nullptr; } -void Sema::FilterAcceptableTemplateNames(LookupResult &R, +void Sema::FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates) { // The set of class templates we've already seen. llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); - NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, + NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, AllowFunctionTemplates); if (!Repl) filter.erase(); @@ -129,7 +129,7 @@ for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates)) return true; - + return false; } @@ -263,7 +263,7 @@ assert((isDependent || !ObjectType->isIncompleteType() || ObjectType->castAs<TagType>()->isBeingDefined()) && "Caller should have completed object type"); - + // Template names cannot appear inside an Objective-C class or object type. if (ObjectType->isObjCObjectOrInterfaceType()) { Found.clear(); @@ -310,7 +310,7 @@ } else { // Perform unqualified name lookup in the current scope. LookupName(Found, S); - + if (!ObjectType.isNull()) AllowFunctionTemplatesInLookup = false; } @@ -755,7 +755,7 @@ Depth, Position, IsParameterPack, Name, Params); Param->setAccess(AS_public); - + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { @@ -882,8 +882,8 @@ if (RequireCompleteDeclContext(SS, SemanticContext)) return true; - // If we're adding a template to a dependent context, we may need to - // rebuilding some of the types used within the template parameter list, + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, // now that we know what the current instantiation is. if (SemanticContext->isDependentContext()) { ContextRAII SavedContext(*this, SemanticContext); @@ -1040,7 +1040,7 @@ // definition, as part of error recovery? return true; } - } + } } else if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); @@ -1107,10 +1107,10 @@ DeclarationName(Name), TemplateParams, NewClass, PrevClassTemplate); NewClass->setDescribedClassTemplate(NewTemplate); - + if (ModulePrivateLoc.isValid()) NewTemplate->setModulePrivate(); - + // Build the type for the class template declaration now. QualType T = NewTemplate->getInjectedClassNameSpecialization(); T = Context.getInjectedClassNameType(NewClass, T); @@ -1201,7 +1201,7 @@ // A default template-argument shall not be specified in a // function template declaration or a function template // definition [...] - // If a friend function template declaration specifies a default + // If a friend function template declaration specifies a default // template-argument, that declaration shall be a definition and shall be // the only declaration of the function template in the translation unit. // (C++98/03 doesn't have this wording; see DR226). @@ -1599,10 +1599,10 @@ return NNSLoc.getTypeLoc().getSourceRange(); } else break; - + NNSLoc = NNSLoc.getPrefix(); } - + return SourceRange(); } @@ -1645,34 +1645,34 @@ bool &IsExplicitSpecialization, bool &Invalid) { IsExplicitSpecialization = false; Invalid = false; - + // The sequence of nested types to which we will match up the template // parameter lists. We first build this list by starting with the type named // by the nested-name-specifier and walking out until we run out of types. SmallVector<QualType, 4> NestedTypes; QualType T; if (SS.getScopeRep()) { - if (CXXRecordDecl *Record + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true))) T = Context.getTypeDeclType(Record); else T = QualType(SS.getScopeRep()->getAsType(), 0); } - + // If we found an explicit specialization that prevents us from needing // 'template<>' headers, this will be set to the location of that // explicit specialization. SourceLocation ExplicitSpecLoc; - + while (!T.isNull()) { NestedTypes.push_back(T); - + // Retrieve the parent of a record type. if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { // If this type is an explicit specialization, we're done. if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { - if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) && + if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) && Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { ExplicitSpecLoc = Spec->getLocation(); break; @@ -1682,25 +1682,25 @@ ExplicitSpecLoc = Record->getLocation(); break; } - + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent())) T = Context.getTypeDeclType(Parent); else T = QualType(); continue; - } - + } + if (const TemplateSpecializationType *TST = T->getAs<TemplateSpecializationType>()) { if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { if (TypeDecl *Parent = dyn_cast<TypeDecl>(Template->getDeclContext())) T = Context.getTypeDeclType(Parent); else T = QualType(); - continue; + continue; } } - + // Look one step prior in a dependent template specialization type. if (const DependentTemplateSpecializationType *DependentTST = T->getAs<DependentTemplateSpecializationType>()) { @@ -1710,27 +1710,27 @@ T = QualType(); continue; } - + // Look one step prior in a dependent name type. if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){ if (NestedNameSpecifier *NNS = DependentName->getQualifier()) T = QualType(NNS->getAsType(), 0); else T = QualType(); continue; } - + // Retrieve the parent of an enumeration type. if (const EnumType *EnumT = T->getAs<EnumType>()) { // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization // check here. EnumDecl *Enum = EnumT->getDecl(); - + // Get to the parent type. if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent())) T = Context.getTypeDeclType(Parent); else - T = QualType(); + T = QualType(); continue; } @@ -1782,21 +1782,21 @@ for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes; ++TypeIdx) { T = NestedTypes[TypeIdx]; - + // Whether we expect a 'template<>' header. bool NeedEmptyTemplateHeader = false; // Whether we expect a template header with parameters. bool NeedNonemptyTemplateHeader = false; - + // For a dependent type, the set of template parameters that we // expect to see. TemplateParameterList *ExpectedTemplateParams = nullptr; // C++0x [temp.expl.spec]p15: - // A member or a member template may be nested within many enclosing - // class templates. In an explicit specialization for such a member, the - // member declaration shall be preceded by a template<> for each + // A member or a member template may be nested within many enclosing + // class templates. In an explicit specialization for such a member, the + // member declaration shall be preceded by a template<> for each // enclosing class template that is explicitly specialized. if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { if (ClassTemplatePartialSpecializationDecl *Partial @@ -1813,38 +1813,38 @@ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { // C++0x [temp.expl.spec]p4: // Members of an explicitly specialized class template are defined - // in the same manner as members of normal classes, and not using - // the template<> syntax. + // in the same manner as members of normal classes, and not using + // the template<> syntax. if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization) NeedEmptyTemplateHeader = true; else continue; } else if (Record->getTemplateSpecializationKind()) { - if (Record->getTemplateSpecializationKind() + if (Record->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && TypeIdx == NumTypes - 1) IsExplicitSpecialization = true; - + continue; } } else if (const TemplateSpecializationType *TST = T->getAs<TemplateSpecializationType>()) { if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { ExpectedTemplateParams = Template->getTemplateParameters(); - NeedNonemptyTemplateHeader = true; + NeedNonemptyTemplateHeader = true; } } else if (T->getAs<DependentTemplateSpecializationType>()) { // FIXME: We actually could/should check the template arguments here // against the corresponding template parameter list. NeedNonemptyTemplateHeader = false; - } - + } + // C++ [temp.expl.spec]p16: - // In an explicit specialization declaration for a member of a class - // template or a member template that ap- pears in namespace scope, the - // member template and some of its enclosing class templates may remain - // unspecialized, except that the declaration shall not explicitly - // specialize a class member template if its en- closing class templates + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates // are not explicitly specialized as well. if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() == 0) { @@ -1854,7 +1854,7 @@ } else SawNonEmptyTemplateParameterList = true; } - + if (NeedEmptyTemplateHeader) { // If we're on the last of the types, and we need a 'template<>' header // here, then it's an explicit specialization. @@ -1864,7 +1864,7 @@ if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() > 0) { // The header has template parameters when it shouldn't. Complain. - Diag(ParamLists[ParamIdx]->getTemplateLoc(), + Diag(ParamLists[ParamIdx]->getTemplateLoc(), diag::err_template_param_list_matches_nontemplate) << T << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), @@ -1896,7 +1896,7 @@ if (ParamIdx < ParamLists.size() && DependsOnTemplateParameters(T, ParamLists[ParamIdx])) ExpectedTemplateParams = nullptr; - else + else continue; } @@ -1912,11 +1912,11 @@ CheckTemplateParameterList(ParamLists[ParamIdx], nullptr, TPC_ClassTemplateMember)) Invalid = true; - + ++ParamIdx; continue; } - + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) << T << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); @@ -1966,23 +1966,23 @@ // not required, and there were any 'template<>' headers, note where the // specialization occurred. if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) - Diag(ExplicitSpecLoc, + Diag(ExplicitSpecLoc, diag::note_explicit_template_spec_does_not_need_header) << NestedTypes.back(); - + // We have a template parameter list with no corresponding scope, which // means that the resulting template declaration can't be instantiated // properly (we'll end up with dependent nodes when we shouldn't). if (!AllExplicitSpecHeaders) Invalid = true; } // C++ [temp.expl.spec]p16: - // In an explicit specialization declaration for a member of a class - // template or a member template that ap- pears in namespace scope, the - // member template and some of its enclosing class templates may remain - // unspecialized, except that the declaration shall not explicitly - // specialize a class member template if its en- closing class templates + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates // are not explicitly specialized as well. if (ParamLists.back()->size() == 0 && CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), @@ -2007,14 +2007,14 @@ << Template->getDeclName(); return; } - + if (OverloadedTemplateStorage *OST = Name.getAsOverloadedTemplate()) { - for (OverloadedTemplateStorage::iterator I = OST->begin(), + for (OverloadedTemplateStorage::iterator I = OST->begin(), IEnd = OST->end(); I != IEnd; ++I) Diag((*I)->getLocation(), diag::note_template_declared_here) << 0 << (*I)->getDeclName(); - + return; } } @@ -2272,7 +2272,7 @@ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) @@ -2299,7 +2299,7 @@ ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); } - + return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } @@ -2314,23 +2314,23 @@ ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.get(); - + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); - + // Determine the tag kind TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { QualType T = Context.getDependentTemplateSpecializationType(Keyword, - DTN->getQualifier(), - DTN->getIdentifier(), + DTN->getQualifier(), + DTN->getIdentifier(), TemplateArgs); - - // Build type-source information. + + // Build type-source information. TypeLocBuilder TLB; DependentTemplateSpecializationTypeLoc SpecTL = TLB.push<DependentTemplateSpecializationTypeLoc>(T); @@ -2354,18 +2354,18 @@ Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4; Diag(TAT->getLocation(), diag::note_declared_at); } - + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) return TypeResult(true); - + // Check the tag kind if (const RecordType *RT = Result->getAs<RecordType>()) { RecordDecl *D = RT->getDecl(); - + IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, TagLoc, Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) @@ -3163,7 +3163,7 @@ // Add the converted template type argument. ArgType = Context.getCanonicalType(ArgType); - + // Objective-C ARC: // If an explicitly-specified template argument type is a lifetime type // with no lifetime qualifier, the __strong lifetime qualifier is inferred. @@ -3174,7 +3174,7 @@ Qs.setObjCLifetime(Qualifiers::OCL_Strong); ArgType = Context.getQualifiedType(ArgType, Qs); } - + Converted.push_back(TemplateArgument(ArgType)); return false; } @@ -3307,7 +3307,7 @@ /// \param Converted the list of template arguments provided for template /// parameters that precede \p Param in the template parameter list. /// -/// \param QualifierLoc Will be set to the nested-name-specifier (with +/// \param QualifierLoc Will be set to the nested-name-specifier (with /// source-location information) that precedes the template name. /// /// \returns the substituted template argument, or NULL if an error occurred. @@ -3659,7 +3659,7 @@ return false; } -/// \brief Diagnose an arity mismatch in the +/// \brief Diagnose an arity mismatch in the static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -3669,7 +3669,7 @@ SourceRange Range; if (NumArgs > NumParams) - Range = SourceRange(TemplateArgs[NumParams].getLocation(), + Range = SourceRange(TemplateArgs[NumParams].getLocation(), TemplateArgs.getRAngleLoc()); S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << (NumArgs > NumParams) @@ -4288,43 +4288,43 @@ if (!S.getLangOpts().CPlusPlus11) return NPV_NotNullPointer; - + // Determine whether we have a constant expression. ExprResult ArgRV = S.DefaultFunctionArrayConversion(Arg); if (ArgRV.isInvalid()) return NPV_Error; Arg = ArgRV.get(); - + Expr::EvalResult EvalResult; SmallVector<PartialDiagnosticAt, 8> Notes; EvalResult.Diag = &Notes; if (!Arg->EvaluateAsRValue(EvalResult, S.Context) || EvalResult.HasSideEffects) { SourceLocation DiagLoc = Arg->getExprLoc(); - + // If our only note is the usual "invalid subexpression" note, just point // the caret at its location rather than producing an essentially // redundant note. if (Notes.size() == 1 && Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr) { DiagLoc = Notes[0].first; Notes.clear(); } - + S.Diag(DiagLoc, diag::err_template_arg_not_address_constant) << Arg->getType() << Arg->getSourceRange(); for (unsigned I = 0, N = Notes.size(); I != N; ++I) S.Diag(Notes[I].first, Notes[I].second); - + S.Diag(Param->getLocation(), diag::note_template_param_here); return NPV_Error; } - + // C++11 [temp.arg.nontype]p1: // - an address constant expression of type std::nullptr_t if (Arg->getType()->isNullPtrType()) return NPV_NullPointer; - + // - a constant expression that evaluates to a null pointer value (4.10); or // - a constant expression that evaluates to a null member pointer value // (4.11); or @@ -4337,7 +4337,7 @@ S.IsQualificationConversion(Arg->getType(), ParamType, false, ObjCLifetimeConversion)) return NPV_NullPointer; - + // The types didn't match, but we know we got a null pointer; complain, // then recover as if the types were correct. S.Diag(Arg->getExprLoc(), diag::err_template_arg_wrongtype_null_constant) @@ -4357,7 +4357,7 @@ S.Diag(Param->getLocation(), diag::note_template_param_here); return NPV_NullPointer; } - + // FIXME: If we ever want to support general, address-constant expressions // as non-type template arguments, we should return the ExprResult here to // be interpreted by the caller. @@ -5068,7 +5068,7 @@ } else if (!Arg->isValueDependent()) { class TmplArgICEDiagnoser : public VerifyICEDiagnoser { QualType T; - + public: TmplArgICEDiagnoser(QualType T) : T(T) { } @@ -5130,23 +5130,23 @@ Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); } else { llvm::APSInt OldValue = Value; - + // Coerce the template argument's value to the value it will have // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) Value = Value.extOrTrunc(AllowedBits); Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); - + // Complain if an unsigned parameter received a negative value. if (IntegerType->isUnsignedIntegerOrEnumerationType() && (OldValue.isSigned() && OldValue.isNegative())) { Diag(Arg->getLocStart(), diag::warn_template_arg_negative) << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); } - + // Complain if we overflowed the template parameter's type. unsigned RequiredBits; if (IntegerType->isUnsignedIntegerOrEnumerationType()) @@ -5165,7 +5165,7 @@ } Converted = TemplateArgument(Context, Value, - ParamType->isEnumeralType() + ParamType->isEnumeralType() ? Context.getCanonicalType(ParamType) : IntegerType); return Arg; @@ -5277,17 +5277,17 @@ Converted = TemplateArgument(Arg); return Arg; } - + switch (isNullPointerValueTemplateArgument(*this, Param, ParamType, Arg)) { case NPV_NotNullPointer: Diag(Arg->getExprLoc(), diag::err_template_arg_not_convertible) << Arg->getType() << ParamType; Diag(Param->getLocation(), diag::note_template_param_here); return ExprError(); - + case NPV_Error: return ExprError(); - + case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); Converted = TemplateArgument(Context.getCanonicalType(ParamType), @@ -5531,7 +5531,7 @@ Context.getTrivialTypeSourceInfo(OrigT, Loc), Loc, Loc); } - + return E; } @@ -5910,7 +5910,7 @@ << Specialized; return true; } - + // C++ [temp.class.spec]p6: // A class template partial specialization may be declared or redeclared // in any namespace scope in which its definition may be defined (14.5.1 @@ -6489,7 +6489,7 @@ Diag(Specialization->getLocation(), diag::err_module_private_specialization) << (isPartialSpecialization? 1 : 0) << FixItHint::CreateRemoval(ModulePrivateLoc); - + // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -6950,7 +6950,7 @@ SpecInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { @@ -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,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; @@ -7604,6 +7599,27 @@ 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, @@ -7635,18 +7651,18 @@ return true; // C++ [dcl.stc]p1: - // A storage-class-specifier shall not be specified in [...] an explicit + // A storage-class-specifier shall not be specified in [...] an explicit // instantiation (14.7.2) directive. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef) << Name; return true; - } else if (D.getDeclSpec().getStorageClassSpec() + } else if (D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_unspecified) { // Complain about then remove the storage class specifier. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_storage_class) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - + D.getMutableDeclSpec().ClearStorageClassSpecs(); } @@ -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,15 @@ // 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 +7812,13 @@ // 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,23 @@ 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. @@ -7984,7 +8029,7 @@ // Create the resulting type. ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind); QualType Result = Context.getDependentNameType(Kwd, NNS, Name); - + // Create type-source location information for this type. TypeLocBuilder TLB; DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(Result); @@ -8000,7 +8045,7 @@ SourceLocation IdLoc) { if (SS.isInvalid()) return true; - + if (TypenameLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TypenameLoc, getLangOpts().CPlusPlus11 ? @@ -8046,11 +8091,11 @@ diag::warn_cxx98_compat_typename_outside_of_template : diag::ext_typename_outside_of_template) << FixItHint::CreateRemoval(TypenameLoc); - + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); - + TemplateName Template = TemplateIn.get(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { // Construct a dependent template specialization type. @@ -8060,10 +8105,10 @@ DTN->getQualifier(), DTN->getIdentifier(), TemplateArgs); - + // Create source-location information for this type. TypeLocBuilder Builder; - DependentTemplateSpecializationTypeLoc SpecTL + DependentTemplateSpecializationTypeLoc SpecTL = Builder.push<DependentTemplateSpecializationTypeLoc>(T); SpecTL.setElaboratedKeywordLoc(TypenameLoc); SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); @@ -8075,11 +8120,11 @@ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } - + QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); if (T.isNull()) return true; - + // Provide source-location information for the template specialization type. TypeLocBuilder Builder; TemplateSpecializationTypeLoc SpecTL @@ -8090,12 +8135,12 @@ SpecTL.setRAngleLoc(RAngleLoc); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); - + T = Context.getElaboratedType(ETK_Typename, SS.getScopeRep(), T); ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T); TL.setElaboratedKeywordLoc(TypenameLoc); TL.setQualifierLoc(SS.getWithLocInContext(Context)); - + TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); return CreateParsedType(T, TSI); } @@ -8140,9 +8185,9 @@ /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType -Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, - NestedNameSpecifierLoc QualifierLoc, + NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc) { CXXScopeSpec SS; @@ -8153,8 +8198,8 @@ // If the nested-name-specifier is dependent and couldn't be // resolved to a type, build a typename type. assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), &II); } @@ -8206,16 +8251,16 @@ case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - return Context.getElaboratedType(ETK_Typename, + return Context.getElaboratedType(ETK_Typename, QualifierLoc.getNestedNameSpecifier(), Context.getTypeDeclType(Type)); } @@ -8282,7 +8327,7 @@ this->Loc = Loc; this->Entity = Entity; } - + ExprResult TransformLambdaExpr(LambdaExpr *E) { // Lambdas never need to be transformed. return E; @@ -8333,15 +8378,15 @@ } bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { - if (SS.isInvalid()) + if (SS.isInvalid()) return true; NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), DeclarationName()); - NestedNameSpecifierLoc Rebuilt + NestedNameSpecifierLoc Rebuilt = Rebuilder.TransformNestedNameSpecifierLoc(QualifierLoc); - if (!Rebuilt) + if (!Rebuilt) return true; SS.Adopt(Rebuilt); @@ -8354,36 +8399,36 @@ TemplateParameterList *Params) { for (unsigned I = 0, N = Params->size(); I != N; ++I) { Decl *Param = Params->getParam(I); - + // There is nothing to rebuild in a type parameter. if (isa<TemplateTypeParmDecl>(Param)) continue; - + // Rebuild the template parameter list of a template template parameter. - if (TemplateTemplateParmDecl *TTP + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { if (RebuildTemplateParamsInCurrentInstantiation( TTP->getTemplateParameters())) return true; - + continue; } - + // Rebuild the type of a non-type template parameter. NonTypeTemplateParmDecl *NTTP = cast<NonTypeTemplateParmDecl>(Param); - TypeSourceInfo *NewTSI - = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(), - NTTP->getLocation(), + TypeSourceInfo *NewTSI + = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(), + NTTP->getLocation(), NTTP->getDeclName()); if (!NewTSI) return true; - + if (NewTSI != NTTP->getTypeSourceInfo()) { NTTP->setTypeSourceInfo(NewTSI); NTTP->setType(NewTSI->getType()); } } - + return false; } Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -862,7 +862,7 @@ << Attr.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) ConsumableAttr(Attr.getRange(), S.Context, DefaultState, Attr.getAttributeSpellingListIndex())); @@ -873,32 +873,32 @@ const AttributeList &Attr) { ASTContext &CurrContext = S.getASTContext(); QualType ThisType = MD->getThisType(CurrContext)->getPointeeType(); - + if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr<ConsumableAttr>()) { S.Diag(Attr.getLoc(), diag::warn_attr_on_unconsumable_class) << RD->getNameAsString(); - + return false; } } - + return true; } static void handleCallableWhenAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return; - + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; - + SmallVector<CallableWhenAttr::ConsumedState, 3> States; for (unsigned ArgIndex = 0; ArgIndex < Attr.getNumArgs(); ++ArgIndex) { CallableWhenAttr::ConsumedState CallableState; - + StringRef StateString; SourceLocation Loc; if (Attr.isArgIdent(ArgIndex)) { @@ -916,10 +916,10 @@ << Attr.getName() << StateString; return; } - + States.push_back(CallableState); } - + D->addAttr(::new (S.Context) CallableWhenAttr(Attr.getRange(), S.Context, States.data(), States.size(), Attr.getAttributeSpellingListIndex())); @@ -929,7 +929,7 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { ParamTypestateAttr::ConsumedState ParamState; - + if (Attr.isArgIdent(0)) { IdentifierLoc *Ident = Attr.getArgAsIdent(0); StringRef StateString = Ident->Ident->getName(); @@ -945,7 +945,7 @@ Attr.getName() << AANT_ArgumentIdentifier; return; } - + // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. @@ -957,7 +957,7 @@ // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) ParamTypestateAttr(Attr.getRange(), S.Context, ParamState, Attr.getAttributeSpellingListIndex())); @@ -967,7 +967,7 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { ReturnTypestateAttr::ConsumedState ReturnState; - + if (Attr.isArgIdent(0)) { IdentifierLoc *IL = Attr.getArgAsIdent(0); if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), @@ -981,7 +981,7 @@ Attr.getName() << AANT_ArgumentIdentifier; return; } - + // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. @@ -993,9 +993,9 @@ //} else if (const CXXConstructorDecl *Constructor = // dyn_cast<CXXConstructorDecl>(D)) { // ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType(); - // + // //} else { - // + // // ReturnType = cast<FunctionDecl>(D)->getCallResultType(); //} // @@ -1006,7 +1006,7 @@ // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) ReturnTypestateAttr(Attr.getRange(), S.Context, ReturnState, Attr.getAttributeSpellingListIndex())); @@ -1016,7 +1016,7 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; - + SetTypestateAttr::ConsumedState NewState; if (Attr.isArgIdent(0)) { IdentifierLoc *Ident = Attr.getArgAsIdent(0); @@ -1031,7 +1031,7 @@ Attr.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) SetTypestateAttr(Attr.getRange(), S.Context, NewState, Attr.getAttributeSpellingListIndex())); @@ -1041,8 +1041,8 @@ const AttributeList &Attr) { if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; - - TestTypestateAttr::ConsumedState TestState; + + TestTypestateAttr::ConsumedState TestState; if (Attr.isArgIdent(0)) { IdentifierLoc *Ident = Attr.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); @@ -1056,7 +1056,7 @@ Attr.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) TestTypestateAttr(Attr.getRange(), S.Context, TestState, Attr.getAttributeSpellingListIndex())); @@ -1655,7 +1655,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { - + // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. if (!isFunctionOrMethodOrBlock(D)) { @@ -1669,7 +1669,7 @@ return; } } - + D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -1679,20 +1679,20 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { /* Returning a Vector Class in Registers - - According to the PPU ABI specifications, a class with a single member of + + According to the PPU ABI specifications, a class with a single member of vector type is returned in memory when used as the return value of a function. This results in inefficient code when implementing vector classes. To return the value in a single vector register, add the vecreturn attribute to the class definition. This attribute is also applicable to struct types. - + Example: - + struct Vector { __vector float xyzw; } __attribute__((vecreturn)); - + Vector Add(Vector lhs, Vector rhs) { Vector result; @@ -2053,7 +2053,7 @@ return; IdentifierLoc *Platform = Attr.getArgAsIdent(0); unsigned Index = Attr.getAttributeSpellingListIndex(); - + IdentifierInfo *II = Platform->Ident; if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) S.Diag(Platform->Loc, diag::warn_availability_unknown_platform) @@ -2214,7 +2214,7 @@ << Attr.getName() << TypeStr; return; } - + // Complain about attempts to use protected visibility on targets // (like Darwin) that don't support it. if (type == VisibilityAttr::Protected && @@ -2287,7 +2287,7 @@ // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); // // In this case it follows tradition and suppresses an error in the above - // case. + // case. S.Diag(D->getLocation(), diag::warn_nsobject_attribute); } D->addAttr(::new (S.Context) @@ -2435,8 +2435,8 @@ << Attr.getName() << 1; return; } - - D->addAttr(::new (S.Context) + + D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } @@ -2736,7 +2736,7 @@ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } - + if (S.getCurFunctionOrMethodDecl()) { S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); Attr.setInvalid(); @@ -2814,10 +2814,10 @@ // Check for supported formats. FormatAttrKind Kind = getFormatAttrKind(Format); - + if (Kind == IgnoredFormat) return; - + if (Kind == InvalidFormat) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << Attr.getName() << II->getName(); @@ -2995,7 +2995,7 @@ if (I->getAnnotation() == Str) return; } - + D->addAttr(::new (S.Context) AnnotateAttr(Attr.getRange(), S.Context, Str, Attr.getAttributeSpellingListIndex())); @@ -3701,7 +3701,7 @@ } } -bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, +bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD) { if (attr.isInvalid()) return true; @@ -3760,7 +3760,7 @@ // method calling convention. TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown; if (FD) - MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member : + MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member : TargetInfo::CCMT_NonMember; CC = TI.getDefaultCallingConv(MT); } @@ -3870,7 +3870,7 @@ << Attr.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; return; } - + if (!checkAttributeNumArgs(S, Attr, 3)) return; @@ -3915,7 +3915,7 @@ << Attr.getName() << 1 << AANT_ArgumentIdentifier; return; } - + if (!checkAttributeNumArgs(S, Attr, 1)) return; @@ -3948,13 +3948,13 @@ } static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isObjCObjectPointerType() || + return type->isDependentType() || + type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); } static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isPointerType() || + return type->isDependentType() || + type->isPointerType() || isValidSubjectOfNSAttribute(S, type); } @@ -4036,7 +4036,7 @@ typeOK = isValidSubjectOfNSReturnsRetainedAttribute(returnType); cf = false; break; - + case AttributeList::AT_NSReturnsAutoreleased: case AttributeList::AT_NSReturnsNotRetained: typeOK = isValidSubjectOfNSAttribute(S, returnType); @@ -4103,7 +4103,7 @@ const AttributeList &attr) { const int EP_ObjCMethod = 1; const int EP_ObjCProperty = 2; - + SourceLocation loc = attr.getLoc(); QualType resultType; if (isa<ObjCMethodDecl>(D)) @@ -4130,7 +4130,7 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, const AttributeList &attr) { ObjCMethodDecl *method = cast<ObjCMethodDecl>(D); - + DeclContext *DC = method->getDeclContext(); if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) @@ -4143,7 +4143,7 @@ << attr.getName() << 1; return; } - + method->addAttr(::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); @@ -4195,7 +4195,7 @@ return; } } - + D->addAttr(::new (S.Context) ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident, Attr.getAttributeSpellingListIndex())); @@ -4209,7 +4209,7 @@ S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; return; } - + D->addAttr(::new (S.Context) ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident, Attr.getAttributeSpellingListIndex())); @@ -4458,7 +4458,7 @@ if (!Attr.isArgExpr(0)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() << AANT_ArgumentIntegerConstant; - return; + return; } // FIXME: Check for decl - it should be void ()(void). @@ -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. @@ -5158,7 +5190,7 @@ case AttributeList::AT_ObjCBoxable: handleObjCBoxable(S, D, Attr); break; - + case AttributeList::AT_CFAuditedTransfer: handleCFAuditedTransferAttr(S, D, Attr); break; @@ -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; @@ -5708,9 +5743,9 @@ if (S.getLangOpts().ObjCAutoRefCount) if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) { // FIXME: we may want to suppress diagnostics for all - // kind of forbidden type messages on unavailable functions. + // kind of forbidden type messages on unavailable functions. if (FD->hasAttr<UnavailableAttr>() && - diag.getForbiddenTypeDiagnostic() == + diag.getForbiddenTypeDiagnostic() == diag::err_arc_array_param_no_ownership) { diag.Triggered = true; return; 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 @@ -736,11 +736,17 @@ return llvm::GlobalVariable::ExternalLinkage; case TSK_ImplicitInstantiation: + // 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::LinkOnceODRLinkage : llvm::Function::InternalLinkage; case TSK_ExplicitInstantiationDefinition: + if (Context.containedInUniqueInstantiation(keyFunction)) + return llvm::GlobalVariable::ExternalLinkage; return !Context.getLangOpts().AppleKext ? llvm::GlobalVariable::WeakODRLinkage : llvm::Function::InternalLinkage; @@ -759,7 +765,11 @@ llvm::GlobalValue::LinkOnceODRLinkage; llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage = llvm::GlobalValue::WeakODRLinkage; - if (RD->hasAttr<DLLExportAttr>()) { + if (RD->hasAttr<UniqueInstantiationAttr>() || + Context.containedInUniqueInstantiation(RD)) { + 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 @@ -8254,6 +8254,19 @@ return getFunctionType(ResType, ArgTypes, EPI); } +bool ASTContext::containedInUniqueInstantiation(const Decl *D) { + while (const DeclContext *DC = D ? D->getDeclContext() : nullptr) { + auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DC); + if (CTSD && CTSD->hasAttr<UniqueInstantiationAttr>()) + return true; + auto *FD = dyn_cast<FunctionDecl>(DC); + if (FD && FD->hasAttr<UniqueInstantiationAttr>()) + return true; + D = FD ? cast<Decl>(FD) : cast_or_null<Decl>(dyn_cast<RecordDecl>(DC)); + } + return false; +} + static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, const FunctionDecl *FD) { if (!FD->isExternallyVisible()) @@ -8267,6 +8280,13 @@ break; case TSK_ExplicitInstantiationDefinition: + if (FD->hasAttr<UniqueInstantiationAttr>() || + Context.containedInUniqueInstantiation(FD)) { + // This translation unit is responsible for emitting a unique + // instantiation of this function regardless of whether or not + // the function is marked inline, so the processing below is irrelevant. + return GVA_StrongExternal; + } return GVA_StrongODR; // C++11 [temp.explicit]p10: @@ -8279,6 +8299,8 @@ return GVA_AvailableExternally; case TSK_ImplicitInstantiation: + if (Context.containedInUniqueInstantiation(FD)) + return GVA_StrongExternal; External = GVA_DiscardableODR; break; } @@ -8369,12 +8391,17 @@ : GVA_StrongExternal; case TSK_ExplicitInstantiationDefinition: + if (VD->hasAttr<UniqueInstantiationAttr>() || + Context.containedInUniqueInstantiation(VD)) + return GVA_StrongExternal; return GVA_StrongODR; case TSK_ExplicitInstantiationDeclaration: return GVA_AvailableExternally; case TSK_ImplicitInstantiation: + if (Context.containedInUniqueInstantiation(VD)) + return GVA_StrongExternal; return GVA_DiscardableODR; } 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 @@ -2428,7 +2428,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< @@ -2533,8 +2534,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]; 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 cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits