[PATCH] D51997: [clang] Make sure attributes on member classes are applied properly

Louis Dionne via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 12 11:14:45 PDT 2018


ldionne added a comment.

This patch is missing support for partial specializations and explicit specializations. The part I don't understand is how to get the `CXXRecordDecl`s to have the right attribute below. Here's the AST dump for the test file with the current patch:

  TranslationUnitDecl 0x7f8a2a00a8e8 <<invalid sloc>> <invalid sloc>
  |-TypedefDecl 0x7f8a2a00b1c0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
  | `-BuiltinType 0x7f8a2a00ae80 '__int128'
  |-TypedefDecl 0x7f8a2a00b228 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
  | `-BuiltinType 0x7f8a2a00aea0 'unsigned __int128'
  |-TypedefDecl 0x7f8a2a00b558 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
  | `-RecordType 0x7f8a2a00b300 '__NSConstantString_tag'
  |   `-CXXRecord 0x7f8a2a00b278 '__NSConstantString_tag'
  |-TypedefDecl 0x7f8a28827600 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
  | `-PointerType 0x7f8a2a00b5b0 'char *'
  |   `-BuiltinType 0x7f8a2a00a980 'char'
  |-TypedefDecl 0x7f8a28827928 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
  | `-ConstantArrayType 0x7f8a288278d0 '__va_list_tag [1]' 1
  |   `-RecordType 0x7f8a288276e0 '__va_list_tag'
  |     `-CXXRecord 0x7f8a28827650 '__va_list_tag'
  |-ClassTemplateDecl 0x7f8a28827ab8 </Users/ldionne/work/clang-attribute/clang/test/SemaCXX/PR38913.cpp:7:1, col:77> col:26 A
  | |-TemplateTypeParmDecl 0x7f8a28827978 <col:10, col:16> col:16 class depth 0 index 0 T
  | |-CXXRecordDecl 0x7f8a28827a30 <col:19, col:77> col:26 struct A definition
  | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveConstructor exists simple trivial needs_implicit
  | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveAssignment exists simple trivial needs_implicit
  | | | `-Destructor simple irrelevant trivial needs_implicit
  | | |-CXXRecordDecl 0x7f8a28827d00 <col:19, col:26> col:26 implicit struct A
  | | `-CXXRecordDecl 0x7f8a28827e38 <col:30, col:74> col:70 struct X definition
  | |   |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | |   | |-MoveConstructor exists simple trivial needs_implicit
  | |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | |   | |-MoveAssignment exists simple trivial needs_implicit
  | |   | `-Destructor simple irrelevant trivial needs_implicit
  | |   |-AbiTagAttr 0x7f8a28827f48 <col:52, col:66> ATAG
  | |   `-CXXRecordDecl 0x7f8a28827fa8 <col:30, col:70> col:70 implicit struct X
  | `-ClassTemplateSpecializationDecl 0x7f8a28828088 <col:1, col:77> col:26 struct A definition
  |   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveConstructor exists simple trivial needs_implicit
  |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveAssignment exists simple trivial needs_implicit
  |   | `-Destructor simple irrelevant trivial needs_implicit
  |   |-TemplateArgument type 'int'
  |   |-CXXRecordDecl 0x7f8a28828280 prev 0x7f8a28828088 <col:19, col:26> col:26 implicit struct A
  |   `-CXXRecordDecl 0x7f8a28828308 <col:30, col:70> col:70 referenced struct X
  |     `-AbiTagAttr 0x7f8a288283b0 <col:52> ATAG
  |-FunctionDecl 0x7f8a2885a200 <line:8:1, col:28> col:12 a 'A<int>::X *()'
  | `-CompoundStmt 0x7f8a2885a328 <col:16, col:28>
  |   `-ReturnStmt 0x7f8a2885a310 <col:18, col:25>
  |     `-ImplicitCastExpr 0x7f8a2885a2f8 <col:25> 'A<int>::X *' <NullToPointer>
  |       `-IntegerLiteral 0x7f8a2885a2d8 <col:25> 'int' 0
  |-ClassTemplateDecl 0x7f8a2885a448 <line:11:1, col:95> col:26 B
  | |-TemplateTypeParmDecl 0x7f8a2885a340 <col:10, col:16> col:16 class depth 0 index 0 T
  | |-CXXRecordDecl 0x7f8a2885a3c0 <col:19, col:95> col:26 struct B definition
  | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveConstructor exists simple trivial needs_implicit
  | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveAssignment exists simple trivial needs_implicit
  | | | `-Destructor simple irrelevant trivial needs_implicit
  | | |-CXXRecordDecl 0x7f8a2885a690 <col:19, col:26> col:26 implicit struct B
  | | `-ClassTemplateDecl 0x7f8a2885a888 <col:30, col:92> col:88 X
  | |   |-TemplateTypeParmDecl 0x7f8a2885a718 <col:39, col:45> col:45 class depth 1 index 0 U
  | |   `-CXXRecordDecl 0x7f8a2885a800 <col:48, col:92> col:88 struct X definition
  | |     |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | |     | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | |     | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | |     | |-MoveConstructor exists simple trivial needs_implicit
  | |     | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | |     | |-MoveAssignment exists simple trivial needs_implicit
  | |     | `-Destructor simple irrelevant trivial needs_implicit
  | |     |-AbiTagAttr 0x7f8a2885aad0 <col:70, col:84> BTAG
  | |     `-CXXRecordDecl 0x7f8a2885ab38 <col:48, col:88> col:88 implicit struct X
  | `-ClassTemplateSpecializationDecl 0x7f8a2885ac18 <col:1, col:95> col:26 struct B definition
  |   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveConstructor exists simple trivial needs_implicit
  |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveAssignment exists simple trivial needs_implicit
  |   | `-Destructor simple irrelevant trivial needs_implicit
  |   |-TemplateArgument type 'int'
  |   |-CXXRecordDecl 0x7f8a2885adf8 prev 0x7f8a2885ac18 <col:19, col:26> col:26 implicit struct B
  |   `-ClassTemplateDecl 0x7f8a2885af88 <col:30, col:88> col:88 X
  |     |-TemplateTypeParmDecl 0x7f8a2885ae80 <col:39, col:45> col:45 class depth 0 index 0 U
  |     |-CXXRecordDecl 0x7f8a2885af00 <col:48, col:88> col:88 struct X
  |     | `-AbiTagAttr 0x7f8a2885b038 <col:70> BTAG
  |     |-ClassTemplateSpecializationDecl 0x7f8a2885b290 <col:30, col:88> col:88 struct X
  |     | |-TemplateArgument type 'int'
  |     | `-AbiTagAttr 0x7f8a2885b390 <col:70> BTAG
  |     `-AbiTagAttr 0x7f8a2885afd8 <col:70> BTAG
  |-FunctionDecl 0x7f8a2885b5d8 <line:12:1, col:33> col:17 b 'B<int>::X<int> *()'
  | `-CompoundStmt 0x7f8a2885b6c0 <col:21, col:33>
  |   `-ReturnStmt 0x7f8a2885b6a8 <col:23, col:30>
  |     `-ImplicitCastExpr 0x7f8a2885b690 <col:30> 'B<int>::X<int> *' <NullToPointer>
  |       `-IntegerLiteral 0x7f8a2885b670 <col:30> 'int' 0
  |-ClassTemplateDecl 0x7f8a2885b7e8 <line:15:1, line:18:1> line:15:26 C
  | |-TemplateTypeParmDecl 0x7f8a2885b6d8 <col:10, col:16> col:16 class depth 0 index 0 T
  | |-CXXRecordDecl 0x7f8a2885b760 <col:19, line:18:1> line:15:26 struct C definition
  | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveConstructor exists simple trivial needs_implicit
  | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveAssignment exists simple trivial needs_implicit
  | | | `-Destructor simple irrelevant trivial needs_implicit
  | | |-CXXRecordDecl 0x7f8a2885ba30 <col:19, col:26> col:26 implicit struct C
  | | |-ClassTemplateDecl 0x7f8a2885bc70 <line:16:3, col:41> col:37 X
  | | | |-TemplateTypeParmDecl 0x7f8a2885bab8 <col:12, col:18> col:18 class depth 1 index 0 U
  | | | |-TemplateTypeParmDecl 0x7f8a2885bb28 <col:21, col:27> col:27 class depth 1 index 1 V
  | | | `-CXXRecordDecl 0x7f8a2885bbe8 <col:30, col:41> col:37 struct X definition
  | | |   |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | | |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | | |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | | |   | |-MoveConstructor exists simple trivial needs_implicit
  | | |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | | |   | |-MoveAssignment exists simple trivial needs_implicit
  | | |   | `-Destructor simple irrelevant trivial needs_implicit
  | | |   `-CXXRecordDecl 0x7f8a2885bf00 <col:30, col:37> col:37 implicit struct X
  | | `-ClassTemplatePartialSpecializationDecl 0x7f8a29803000 <line:17:3, col:73> col:61 struct X definition
  | |   |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | |   | |-MoveConstructor exists simple trivial needs_implicit
  | |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | |   | |-MoveAssignment exists simple trivial needs_implicit
  | |   | `-Destructor simple irrelevant trivial needs_implicit
  | |   |-TemplateArgument type 'int'
  | |   |-TemplateArgument type 'type-parameter-1-0'
  | |   |-TemplateTypeParmDecl 0x7f8a2885bfa8 <col:12, col:18> col:18 referenced class depth 1 index 0 V
  | |   |-AbiTagAttr 0x7f8a29803138 <col:43, col:57> CTAG
  | |   `-CXXRecordDecl 0x7f8a298032b8 <col:21, col:61> col:61 implicit struct X
  | `-ClassTemplateSpecializationDecl 0x7f8a29803398 <line:15:1, line:18:1> line:15:26 struct C definition
  |   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveConstructor exists simple trivial needs_implicit
  |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveAssignment exists simple trivial needs_implicit
  |   | `-Destructor simple irrelevant trivial needs_implicit
  |   |-TemplateArgument type 'int'
  |   |-CXXRecordDecl 0x7f8a29803578 prev 0x7f8a29803398 <col:19, col:26> col:26 implicit struct C
  |   `-ClassTemplateDecl 0x7f8a298037b0 <line:16:3, col:37> col:37 X
  |     |-TemplateTypeParmDecl 0x7f8a29803600 <col:12, col:18> col:18 class depth 0 index 0 U
  |     |-TemplateTypeParmDecl 0x7f8a29803668 <col:21, col:27> col:27 class depth 0 index 1 V
  |     |-CXXRecordDecl 0x7f8a29803728 <col:30, col:37> col:37 struct X
  |     `-ClassTemplateSpecializationDecl 0x7f8a29803e30 <col:3, col:37> col:37 struct X
  |       |-TemplateArgument type 'int'
  |       `-TemplateArgument type 'long'
  |-FunctionDecl 0x7f8a29804990 <line:19:1, col:39> col:23 c 'C<int>::X<int, long> *()'
  | `-CompoundStmt 0x7f8a29804a78 <col:27, col:39>
  |   `-ReturnStmt 0x7f8a29804a60 <col:29, col:36>
  |     `-ImplicitCastExpr 0x7f8a29804a48 <col:36> 'C<int>::X<int, long> *' <NullToPointer>
  |       `-IntegerLiteral 0x7f8a29804a28 <col:36> 'int' 0
  |-ClassTemplateDecl 0x7f8a29804b98 <line:22:1, line:25:1> line:22:26 D
  | |-TemplateTypeParmDecl 0x7f8a29804a90 <col:10, col:16> col:16 class depth 0 index 0 T
  | |-CXXRecordDecl 0x7f8a29804b10 <col:19, line:25:1> line:22:26 struct D definition
  | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveConstructor exists simple trivial needs_implicit
  | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | | | |-MoveAssignment exists simple trivial needs_implicit
  | | | `-Destructor simple irrelevant trivial needs_implicit
  | | |-CXXRecordDecl 0x7f8a29804de0 <col:19, col:26> col:26 implicit struct D
  | | |-ClassTemplateDecl 0x7f8a29804f78 <line:23:3, col:32> col:28 X
  | | | |-TemplateTypeParmDecl 0x7f8a29804e68 <col:12, col:18> col:18 class depth 1 index 0 U
  | | | |-CXXRecordDecl 0x7f8a29804ef0 <col:21, col:32> col:28 struct X definition
  | | | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | | | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | | | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | | | | | |-MoveConstructor exists simple trivial needs_implicit
  | | | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | | | | | |-MoveAssignment exists simple trivial needs_implicit
  | | | | | `-Destructor simple irrelevant trivial needs_implicit
  | | | | `-CXXRecordDecl 0x7f8a298051c0 <col:21, col:28> col:28 implicit struct X
  | | | `-ClassTemplateSpecialization 0x7f8a298052c0 'X'
  | | `-ClassTemplateSpecializationDecl 0x7f8a298052c0 <line:24:3, col:63> col:54 struct X definition
  | |   |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  | |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  | |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  | |   | |-MoveConstructor exists simple trivial needs_implicit
  | |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  | |   | |-MoveAssignment exists simple trivial needs_implicit
  | |   | `-Destructor simple irrelevant trivial needs_implicit
  | |   |-TemplateArgument type 'int'
  | |   |-AbiTagAttr 0x7f8a29805470 <col:36, col:50> DTAG
  | |   `-CXXRecordDecl 0x7f8a298055c8 <col:14, col:54> col:54 implicit struct X
  | `-ClassTemplateSpecializationDecl 0x7f8a298056a8 <line:22:1, line:25:1> line:22:26 struct D definition
  |   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  |   | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  |   | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveConstructor exists simple trivial needs_implicit
  |   | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  |   | |-MoveAssignment exists simple trivial needs_implicit
  |   | `-Destructor simple irrelevant trivial needs_implicit
  |   |-TemplateArgument type 'int'
  |   |-CXXRecordDecl 0x7f8a2a03b6a8 prev 0x7f8a298056a8 <col:19, col:26> col:26 implicit struct D
  |   |-ClassTemplateDecl 0x7f8a2a03b838 <line:23:3, col:28> col:28 X
  |   | |-TemplateTypeParmDecl 0x7f8a2a03b730 <col:12, col:18> col:18 class depth 0 index 0 U
  |   | |-CXXRecordDecl 0x7f8a2a03b7b0 <col:21, col:28> col:28 struct X
  |   | `-ClassTemplateSpecialization 0x7f8a2a03ba18 'X'
  |   `-ClassTemplateSpecializationDecl 0x7f8a2a03ba18 <line:24:3, col:63> col:54 struct X definition
  |     |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
  |     | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
  |     | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
  |     | |-MoveConstructor exists simple trivial needs_implicit
  |     | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
  |     | |-MoveAssignment exists simple trivial needs_implicit
  |     | `-Destructor simple irrelevant trivial needs_implicit
  |     |-TemplateArgument type 'int'
  |     |-AbiTagAttr 0x7f8a2a03bbe0 <col:36> DTAG
  |     `-CXXRecordDecl 0x7f8a2a03bcb0 prev 0x7f8a2a03ba18 <col:14, col:54> col:54 implicit struct X
  `-FunctionDecl 0x7f8a2a03bf98 <line:26:1, col:33> col:17 d 'D<int>::X<int> *()'
    `-CompoundStmt 0x7f8a2a03c080 <col:21, col:33>
      `-ReturnStmt 0x7f8a2a03c068 <col:23, col:30>
        `-ImplicitCastExpr 0x7f8a2a03c050 <col:30> 'D<int>::X<int> *' <NullToPointer>
          `-IntegerLiteral 0x7f8a2a03c030 <col:30> 'int' 0

As you can see, the `CXXRecordDecl`s have the right attributes for the member class and member class template cases, but not for the partial and explicit specializations.



================
Comment at: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp:2971
   InstD->setExternLoc(D->getExternLoc());
   InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
 
----------------
I tried a couple variations of things like:

```
SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, InstD, LateAttrs, StartingScope);
```

and 

```
SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, ClassTemplate->getTemplatedDecl(), LateAttrs, StartingScope);
```

For some reason, none of them end up instantiating the attribute on the `CXXRecordDecl` that is used to determine the mangling.



================
Comment at: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp:3247
   InstPartialSpec->setTypeAsWritten(WrittenTy);
 
   // Check the completed partial specialization.
----------------
I tried adding

```
SemaRef.InstantiateAttrsForDecl(TemplateArgs, ClassTemplate->getTemplatedDecl(), InstPartialSpec, LateAttrs, StartingScope);
```

here, but just like for explicit specializations, that doesn't instantiate the attributes on the `CXXRecordDecl` used to determine mangling.



================
Comment at: clang/test/SemaCXX/PR38913.cpp:19
+};
+C<int>::X<int, long>* c() { return 0; } // CHECK-DAG: @_Z1cB4CTAGv
+
----------------
This test is failing in the current iteration of the patch.


================
Comment at: clang/test/SemaCXX/PR38913.cpp:26
+};
+D<int>::X<int>* d() { return 0; } // CHECK-DAG: @_Z1dB4DTAGv
----------------
This test is failing in the current iteration of the patch.


Repository:
  rC Clang

https://reviews.llvm.org/D51997





More information about the cfe-commits mailing list