This change addresses three issues:
- A failure to propagate a MSInheritanceAttr prior to it being required by an explicit class template instantiation definition.
- The same MSInheritanceAttr attribute being attached to the same ClassTemplateSpecializationDecl twice.
- MSInheritanceAttr attributes were not being cloned nor marked as inherited when added to new template instantiation declarations.
Sema::ActOnExplicitInstantiation() is responsible for the construction of ClassTemplateSpecializationDecl nodes for explicit template instantiation declarations and definitions. When invoked when a prior declaration node corresponding to an implicit instantiation exists, the prior declaration node is repurposed to represent the explicit instantiation declaration or definition. When no previous declaration node exists or when the previous node corresponds to an explicit declaration, a new node is allocated. Previously, in either case, the function attempted to propagate any existing MSInheritanceAttr attribute from the previous node, but did so regardless of whether the previous node was reused (in which case the repurposed previous node would gain a second attachment of the attribute; the second issue listed above) or a new node was created. In the latter case, the attribute was not propagated before it was required to be present when compiling for C++17 or later (the first issue listed above). The absent attribute resulted in an assertion failure that occurred during instantiation of the specialization definition when attempting to complete the definition in order to determine its alignment so as to resolve a lookup for a deallocation function for a virtual destructor. This change addresses both issues by propagating the attribute closer in time to when a new ClassTemplateSpecializationDecl node is created and only when such a node is newly created.
hasAttr() is O(n) in the attribute list size, so I would recommend this pattern: