r343790 - [clang] Add the exclude_from_explicit_instantiation attribute

Louis Dionne via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 5 09:29:40 PDT 2018


I just saw this. Simon Pilgrim already fixed it in r343846. Thanks Simon!

Louis

> On Oct 4, 2018, at 22:02, Galina Kistanova <gkistanova at gmail.com> wrote:
> 
> Hello Louis,
> 
> This commit broke build step on one of our builders:
> http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/13042 <http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/13042>
> 
> . . .
> FAILED: tools/clang/lib/Sema/CMakeFiles/clangSema.dir/SemaExprCXX.cpp.obj 
> C:\PROGRA~2\MICROS~1.0\VC\bin\amd64\cl.exe  /nologo /TP -DEXPENSIVE_CHECKS -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_DEBUG -D_GNU_SOURCE -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools\clang\lib\Sema -IC:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\lib\Sema -IC:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\include -Itools\clang\include -Iinclude -IC:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:strictStrings /Oi /Zc:rvalueCast /W4 -wd4141 -wd4146 -wd4180 -wd4244 -wd4258 -wd4267 -wd4291 -wd4345 -wd4351 -wd4355 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4800 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4324 -w14062 -we4238 /MDd /Zi /Ob0 /Od /RTC1    /EHs-c- /GR- /showIncludes /Fotools\clang\lib\Sema\CMakeFiles\clangSema.dir\SemaExprCXX.cpp.obj /Fdtools\clang\lib\Sema\CMakeFiles\clangSema.dir\clangSema.pdb /FS -c C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\lib\Sema\SemaExprCXX.cpp
> C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\lib\Sema\SemaExprCXX.cpp : fatal error C1128: number of sections exceeded object file format limit: compile with /bigobj
> 
> 
> Please have a look?
> The builder was already red and did not send notifications on this.
> 
> Thanks
> 
> Galina
> 
> On Thu, Oct 4, 2018 at 8:51 AM Louis Dionne via cfe-commits <cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>> wrote:
> Author: ldionne
> Date: Thu Oct  4 08:49:42 2018
> New Revision: 343790
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=343790&view=rev <http://llvm.org/viewvc/llvm-project?rev=343790&view=rev>
> Log:
> [clang] Add the exclude_from_explicit_instantiation attribute
> 
> Summary:
> This attribute allows excluding a member of a class template from being part
> of an explicit template instantiation of that class template. This also makes
> sure that code using such a member will not take for granted that an external
> instantiation exists in another translation unit. The attribute was discussed
> on cfe-dev at [1] and is primarily motivated by the removal of always_inline
> in libc++ to control what's part of the ABI (see links in [1]).
> 
> [1]: http://lists.llvm.org/pipermail/cfe-dev/2018-August/059024.html <http://lists.llvm.org/pipermail/cfe-dev/2018-August/059024.html>
> 
> rdar://problem/43428125
> 
> Reviewers: rsmith
> 
> Subscribers: dexonsmith, cfe-commits
> 
> Differential Revision: https://reviews.llvm.org/D51789 <https://reviews.llvm.org/D51789>
> 
> Added:
>     cfe/trunk/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp
>     cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
>     cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.explicit_instantiation.cpp
>     cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.extern_declaration.cpp
>     cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.merge_redeclarations.cpp
> Modified:
>     cfe/trunk/include/clang/Basic/Attr.td
>     cfe/trunk/include/clang/Basic/AttrDocs.td
>     cfe/trunk/lib/Sema/Sema.cpp
>     cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>     cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>     cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> 
> Modified: cfe/trunk/include/clang/Basic/Attr.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=343790&r1=343789&r2=343790&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=343790&r1=343789&r2=343790&view=diff>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Attr.td (original)
> +++ cfe/trunk/include/clang/Basic/Attr.td Thu Oct  4 08:49:42 2018
> @@ -3042,6 +3042,13 @@ def InternalLinkage : InheritableAttr {
>    let Documentation = [InternalLinkageDocs];
>  }
> 
> +def ExcludeFromExplicitInstantiation : InheritableAttr {
> +  let Spellings = [Clang<"exclude_from_explicit_instantiation">];
> +  let Subjects = SubjectList<[Var, Function, CXXRecord]>;
> +  let Documentation = [ExcludeFromExplicitInstantiationDocs];
> +  let MeaningfulToClassTemplateDefinition = 1;
> +}
> +
>  def Reinitializes : InheritableAttr {
>    let Spellings = [Clang<"reinitializes", 0>];
>    let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
> 
> Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=343790&r1=343789&r2=343790&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=343790&r1=343789&r2=343790&view=diff>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
> +++ cfe/trunk/include/clang/Basic/AttrDocs.td Thu Oct  4 08:49:42 2018
> @@ -2975,6 +2975,68 @@ This can be used to contain the ABI of a
>    }];
>  }
> 
> +def ExcludeFromExplicitInstantiationDocs : Documentation {
> +  let Category = DocCatFunction;
> +  let Content = [{
> +The ``exclude_from_explicit_instantiation`` attribute opts-out a member of a
> +class template from being part of explicit template instantiations of that
> +class template. This means that an explicit instantiation will not instantiate
> +members of the class template marked with the attribute, but also that code
> +where an extern template declaration of the enclosing class template is visible
> +will not take for granted that an external instantiation of the class template
> +would provide those members (which would otherwise be a link error, since the
> +explicit instantiation won't provide those members). For example, let's say we
> +don't want the ``data()`` method to be part of libc++'s ABI. To make sure it
> +is not exported from the dylib, we give it hidden visibility:
> +
> +  .. code-block:: c++
> +
> +    // in <string>
> +    template <class CharT>
> +    class basic_string {
> +    public:
> +      __attribute__((__visibility__("hidden")))
> +      const value_type* data() const noexcept { ... }
> +    };
> +
> +    template class basic_string<char>;
> +
> +Since an explicit template instantiation declaration for ``basic_string<char>``
> +is provided, the compiler is free to assume that ``basic_string<char>::data()``
> +will be provided by another translation unit, and it is free to produce an
> +external call to this function. However, since ``data()`` has hidden visibility
> +and the explicit template instantiation is provided in a shared library (as
> +opposed to simply another translation unit), ``basic_string<char>::data()``
> +won't be found and a link error will ensue. This happens because the compiler
> +assumes that ``basic_string<char>::data()`` is part of the explicit template
> +instantiation declaration, when it really isn't. To tell the compiler that
> +``data()`` is not part of the explicit template instantiation declaration, the
> +``exclude_from_explicit_instantiation`` attribute can be used:
> +
> +  .. code-block:: c++
> +
> +    // in <string>
> +    template <class CharT>
> +    class basic_string {
> +    public:
> +      __attribute__((__visibility__("hidden")))
> +      __attribute__((exclude_from_explicit_instantiation))
> +      const value_type* data() const noexcept { ... }
> +    };
> +
> +    template class basic_string<char>;
> +
> +Now, the compiler won't assume that ``basic_string<char>::data()`` is provided
> +externally despite there being an explicit template instantiation declaration:
> +the compiler will implicitly instantiate ``basic_string<char>::data()`` in the
> +TUs where it is used.
> +
> +This attribute can be used on static and non-static member functions of class
> +templates, static data members of class templates and member classes of class
> +templates.
> +  }];
> +}
> +
>  def DisableTailCallsDocs : Documentation {
>    let Category = DocCatFunction;
>    let Content = [{
> 
> Modified: cfe/trunk/lib/Sema/Sema.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=343790&r1=343789&r2=343790&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=343790&r1=343789&r2=343790&view=diff>
> ==============================================================================
> --- cfe/trunk/lib/Sema/Sema.cpp (original)
> +++ cfe/trunk/lib/Sema/Sema.cpp Thu Oct  4 08:49:42 2018
> @@ -644,7 +644,8 @@ void Sema::getUndefinedButUsed(
>          continue;
>        if (FD->isExternallyVisible() &&
>            !isExternalWithNoLinkageType(FD) &&
> -          !FD->getMostRecentDecl()->isInlined())
> +          !FD->getMostRecentDecl()->isInlined() &&
> +          !FD->hasAttr<ExcludeFromExplicitInstantiationAttr>())
>          continue;
>        if (FD->getBuiltinID())
>          continue;
> @@ -654,7 +655,8 @@ void Sema::getUndefinedButUsed(
>          continue;
>        if (VD->isExternallyVisible() &&
>            !isExternalWithNoLinkageType(VD) &&
> -          !VD->getMostRecentDecl()->isInline())
> +          !VD->getMostRecentDecl()->isInline() &&
> +          !VD->hasAttr<ExcludeFromExplicitInstantiationAttr>())
>          continue;
> 
>        // Skip VarDecls that lack formal definitions but which we know are in
> 
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=343790&r1=343789&r2=343790&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=343790&r1=343789&r2=343790&view=diff>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Oct  4 08:49:42 2018
> @@ -6512,6 +6512,9 @@ static void ProcessDeclAttribute(Sema &S
>    case ParsedAttr::AT_InternalLinkage:
>      handleInternalLinkageAttr(S, D, AL);
>      break;
> +  case ParsedAttr::AT_ExcludeFromExplicitInstantiation:
> +    handleSimpleAttribute<ExcludeFromExplicitInstantiationAttr>(S, D, AL);
> +    break;
>    case ParsedAttr::AT_LTOVisibilityPublic:
>      handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL);
>      break;
> 
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=343790&r1=343789&r2=343790&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=343790&r1=343789&r2=343790&view=diff>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Oct  4 08:49:42 2018
> @@ -2574,10 +2574,14 @@ Sema::InstantiateClassMembers(SourceLoca
>    for (auto *D : Instantiation->decls()) {
>      bool SuppressNew = false;
>      if (auto *Function = dyn_cast<FunctionDecl>(D)) {
> -      if (FunctionDecl *Pattern
> -            = Function->getInstantiatedFromMemberFunction()) {
> -        MemberSpecializationInfo *MSInfo
> -          = Function->getMemberSpecializationInfo();
> +      if (FunctionDecl *Pattern =
> +              Function->getInstantiatedFromMemberFunction()) {
> +
> +        if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
> +          continue;
> +
> +        MemberSpecializationInfo *MSInfo =
> +            Function->getMemberSpecializationInfo();
>          assert(MSInfo && "No member specialization information?");
>          if (MSInfo->getTemplateSpecializationKind()
>                                                   == TSK_ExplicitSpecialization)
> @@ -2618,6 +2622,9 @@ Sema::InstantiateClassMembers(SourceLoca
>          continue;
> 
>        if (Var->isStaticDataMember()) {
> +        if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
> +          continue;
> +
>          MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
>          assert(MSInfo && "No member specialization information?");
>          if (MSInfo->getTemplateSpecializationKind()
> @@ -2649,6 +2656,9 @@ Sema::InstantiateClassMembers(SourceLoca
>          }
>        }
>      } else if (auto *Record = dyn_cast<CXXRecordDecl>(D)) {
> +      if (Record->hasAttr<ExcludeFromExplicitInstantiationAttr>())
> +        continue;
> +
>        // Always skip the injected-class-name, along with any
>        // redeclarations of nested classes, since both would cause us
>        // to try to instantiate the members of a class twice.
> 
> Added: cfe/trunk/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp?rev=343790&view=auto <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp?rev=343790&view=auto>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp Thu Oct  4 08:49:42 2018
> @@ -0,0 +1,84 @@
> +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -O0 -o - %s | FileCheck %s
> +
> +// Test that we do not assume that entities marked with the
> +// exclude_from_explicit_instantiation attribute are instantiated
> +// in another TU when an extern template instantiation declaration
> +// is present. We test that by making sure that definitions are
> +// generated in this TU despite there being an extern template
> +// instantiation declaration, which is normally not the case.
> +
> +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
> +
> +template <class T>
> +struct Foo {
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION        inline void non_static_member_function1();
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION               void non_static_member_function2();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static inline void static_member_function1();
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static        void static_member_function2();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static        int static_data_member;
> +
> +  struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION member_class1 {
> +    static void static_member_function() { }
> +  };
> +
> +  struct member_class2 {
> +    EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void static_member_function() { }
> +  };
> +};
> +
> +template <class T> inline void Foo<T>::non_static_member_function1() { }
> +template <class T>        void Foo<T>::non_static_member_function2() { }
> +
> +template <class T> inline void Foo<T>::static_member_function1() { }
> +template <class T>        void Foo<T>::static_member_function2() { }
> +
> +template <class T>        int Foo<T>::static_data_member = 0;
> +
> +extern template struct Foo<int>;
> +
> +void use() {
> +  Foo<int> f;
> +
> +  // An inline non-static member function marked with the attribute is not
> +  // part of the extern template declaration, so a definition must be emitted
> +  // in this TU.
> +  // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE27non_static_member_function1Ev
> +  f.non_static_member_function1();
> +
> +  // A non-inline non-static member function marked with the attribute is
> +  // not part of the extern template declaration, so a definition must be
> +  // emitted in this TU.
> +  // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE27non_static_member_function2Ev
> +  f.non_static_member_function2();
> +
> +  // An inline static member function marked with the attribute is not
> +  // part of the extern template declaration, so a definition must be
> +  // emitted in this TU.
> +  // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE23static_member_function1Ev
> +  Foo<int>::static_member_function1();
> +
> +  // A non-inline static member function marked with the attribute is not
> +  // part of the extern template declaration, so a definition must be
> +  // emitted in this TU.
> +  // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE23static_member_function2Ev
> +  Foo<int>::static_member_function2();
> +
> +  // A static data member marked with the attribute is not part of the
> +  // extern template declaration, so a definition must be emitted in this TU.
> +  // CHECK-DAG: @_ZN3FooIiE18static_data_memberE = linkonce_odr global
> +  int& odr_use = Foo<int>::static_data_member;
> +
> +  // A member class marked with the attribute is not part of the extern
> +  // template declaration (it is not recursively instantiated), so its member
> +  // functions must be emitted in this TU.
> +  // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE13member_class122static_member_functionEv
> +  Foo<int>::member_class1::static_member_function();
> +
> +  // A member function marked with the attribute in a member class is not
> +  // part of the extern template declaration of the parent class template, so
> +  // it must be emitted in this TU.
> +  // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE13member_class222static_member_functionEv
> +  Foo<int>::member_class2::static_member_function();
> +}
> 
> Modified: cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=343790&r1=343789&r2=343790&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=343790&r1=343789&r2=343790&view=diff>
> ==============================================================================
> --- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test (original)
> +++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test Thu Oct  4 08:49:42 2018
> @@ -2,7 +2,7 @@
> 
>  // The number of supported attributes should never go down!
> 
> -// CHECK: #pragma clang attribute supports 128 attributes:
> +// CHECK: #pragma clang attribute supports 129 attributes:
>  // CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
>  // CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
>  // CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
> @@ -47,6 +47,7 @@
>  // CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method)
>  // CHECK-NEXT: EnableIf (SubjectMatchRule_function)
>  // CHECK-NEXT: EnumExtensibility (SubjectMatchRule_enum)
> +// CHECK-NEXT: ExcludeFromExplicitInstantiation (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
>  // CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
>  // CHECK-NEXT: FlagEnum (SubjectMatchRule_enum)
>  // CHECK-NEXT: Flatten (SubjectMatchRule_function)
> 
> Added: cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp?rev=343790&view=auto <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp?rev=343790&view=auto>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.diagnose_on_undefined_entity.cpp Thu Oct  4 08:49:42 2018
> @@ -0,0 +1,36 @@
> +// RUN: %clang_cc1 -fsyntax-only -Wundefined-func-template -Wundefined-var-template -verify %s
> +
> +// Test that a diagnostic is emitted when an entity marked with the
> +// exclude_from_explicit_instantiation attribute is not defined in
> +// the current TU but it is used (and it is hence implicitly
> +// instantiated).
> +
> +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
> +
> +template <class T>
> +struct Foo {
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void non_static_member_function(); // expected-note{{forward declaration of template entity is here}}
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void static_member_function(); // expected-note{{forward declaration of template entity is here}}
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static int static_data_member; // expected-note{{forward declaration of template entity is here}}
> +  struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION nested {
> +    static int static_member_function(); // expected-note{{forward declaration of template entity is here}}
> +  };
> +};
> +
> +extern template struct Foo<int>;
> +
> +void use() {
> +  Foo<int> foo;
> +
> +  foo.non_static_member_function(); // expected-warning{{instantiation of function 'Foo<int>::non_static_member_function' required here, but no definition is available}}
> +  // expected-note at -1 {{add an explicit instantiation}}
> +
> +  Foo<int>::static_member_function(); // expected-warning{{instantiation of function 'Foo<int>::static_member_function' required here, but no definition is available}}
> +  // expected-note at -1 {{add an explicit instantiation}}
> +
> +  (void)Foo<int>::static_data_member; // expected-warning{{instantiation of variable 'Foo<int>::static_data_member' required here, but no definition is available}}
> +  // expected-note at -1 {{add an explicit instantiation}}
> +
> +  Foo<int>::nested::static_member_function(); // expected-warning{{instantiation of function 'Foo<int>::nested::static_member_function' required here, but no definition is available}}
> +  // expected-note at -1 {{add an explicit instantiation}}
> +}
> 
> Added: cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.explicit_instantiation.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.explicit_instantiation.cpp?rev=343790&view=auto <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.explicit_instantiation.cpp?rev=343790&view=auto>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.explicit_instantiation.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.explicit_instantiation.cpp Thu Oct  4 08:49:42 2018
> @@ -0,0 +1,45 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify %s
> +
> +// Test that explicit instantiations do not instantiate entities
> +// marked with the exclude_from_explicit_instantiation attribute.
> +
> +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
> +
> +template <class T>
> +struct Foo {
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION inline void non_static_member_function1();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void non_static_member_function2();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static inline void static_member_function1();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void static_member_function2();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static int static_data_member;
> +
> +  struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION member_class1 {
> +    static void non_static_member_function() { using Fail = typename T::fail; }
> +  };
> +
> +  struct member_class2 {
> +    EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void non_static_member_function() { using Fail = typename T::fail; }
> +  };
> +};
> +
> +template <class T>
> +inline void Foo<T>::non_static_member_function1() { using Fail = typename T::fail; }
> +
> +template <class T>
> +void Foo<T>::non_static_member_function2() { using Fail = typename T::fail; }
> +
> +template <class T>
> +inline void Foo<T>::static_member_function1() { using Fail = typename T::fail; }
> +
> +template <class T>
> +void Foo<T>::static_member_function2() { using Fail = typename T::fail; }
> +
> +template <class T>
> +int Foo<T>::static_data_member = T::fail;
> +
> +// expected-no-diagnostics
> +template struct Foo<int>;
> 
> Added: cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.extern_declaration.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.extern_declaration.cpp?rev=343790&view=auto <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.extern_declaration.cpp?rev=343790&view=auto>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.extern_declaration.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.extern_declaration.cpp Thu Oct  4 08:49:42 2018
> @@ -0,0 +1,69 @@
> +// RUN: %clang_cc1 -Wno-unused-local-typedef -fsyntax-only -verify %s
> +
> +// Test that extern instantiation declarations cause members marked with
> +// the exclude_from_explicit_instantiation attribute to be instantiated in
> +// the current TU.
> +
> +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
> +
> +template <class T>
> +struct Foo {
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION inline void non_static_member_function1();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void non_static_member_function2();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static inline void static_member_function1();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void static_member_function2();
> +
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION static int static_data_member;
> +
> +  struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION member_class1 {
> +    static void static_member_function() {
> +      using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +    }
> +  };
> +
> +  struct member_class2 {
> +    EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void static_member_function() {
> +      using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +    }
> +  };
> +};
> +
> +template <class T>
> +inline void Foo<T>::non_static_member_function1() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +template <class T>
> +void Foo<T>::non_static_member_function2() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +template <class T>
> +inline void Foo<T>::static_member_function1() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +template <class T>
> +void Foo<T>::static_member_function2() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +template <class T>
> +int Foo<T>::static_data_member = T::invalid; // expected-error{{no member named 'invalid' in 'Empty'}}
> +
> +struct Empty { };
> +extern template struct Foo<Empty>;
> +
> +int main() {
> +  Foo<Empty> foo;
> +  foo.non_static_member_function1();                   // expected-note{{in instantiation of}}
> +  foo.non_static_member_function2();                   // expected-note{{in instantiation of}}
> +  Foo<Empty>::static_member_function1();               // expected-note{{in instantiation of}}
> +  Foo<Empty>::static_member_function2();               // expected-note{{in instantiation of}}
> +  (void)foo.static_data_member;                        // expected-note{{in instantiation of}}
> +  Foo<Empty>::member_class1::static_member_function(); // expected-note{{in instantiation of}}
> +  Foo<Empty>::member_class2::static_member_function(); // expected-note{{in instantiation of}}
> +}
> 
> Added: cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.merge_redeclarations.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.merge_redeclarations.cpp?rev=343790&view=auto <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.merge_redeclarations.cpp?rev=343790&view=auto>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.merge_redeclarations.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-exclude_from_explicit_instantiation.merge_redeclarations.cpp Thu Oct  4 08:49:42 2018
> @@ -0,0 +1,43 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify %s
> +
> +// Test that we properly merge the exclude_from_explicit_instantiation
> +// attribute on redeclarations.
> +
> +#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
> +
> +template <class T>
> +struct Foo {
> +  // Declaration without the attribute, definition with the attribute.
> +  void func1();
> +
> +  // Declaration with the attribute, definition without the attribute.
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void func2();
> +
> +  // Declaration with the attribute, definition with the attribute.
> +  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void func3();
> +};
> +
> +template <class T>
> +EXCLUDE_FROM_EXPLICIT_INSTANTIATION void Foo<T>::func1() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +template <class T>
> +void Foo<T>::func2() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +template <class T>
> +EXCLUDE_FROM_EXPLICIT_INSTANTIATION void Foo<T>::func3() {
> +  using Fail = typename T::invalid; // expected-error{{no type named 'invalid' in 'Empty'}}
> +}
> +
> +struct Empty { };
> +extern template struct Foo<Empty>;
> +
> +int main() {
> +  Foo<Empty> foo;
> +  foo.func1(); // expected-note{{in instantiation of}}
> +  foo.func2(); // expected-note{{in instantiation of}}
> +  foo.func3(); // expected-note{{in instantiation of}}
> +}
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20181005/9addb6d7/attachment-0001.html>


More information about the cfe-commits mailing list