loladiro updated this revision to Diff 42100. loladiro added a comment. Address stylistic concerns brought up by David
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,44 @@ +// 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: 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 @@ -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,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: @@ -8369,6 +8387,9 @@ : GVA_StrongExternal; case TSK_ExplicitInstantiationDefinition: + if (VD->hasAttr<UniqueInstantiationAttr>() || + 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 @@ -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