relative to the scope of the class. */
pop_to_parent_deferring_access_checks ();
+ /* A vector to hold members marked with attribute used. */
+ auto_vec<tree> used;
+
/* Now members are processed in the order of declaration. */
for (member = CLASSTYPE_DECL_LIST (pattern);
member; member = TREE_CHAIN (member))
finish_member_declaration (r);
/* Instantiate members marked with attribute used. */
if (r != error_mark_node && DECL_PRESERVE_P (r))
- mark_used (r);
+ used.safe_push (r);
if (TREE_CODE (r) == FUNCTION_DECL
&& DECL_OMP_DECLARE_REDUCTION_P (r))
cp_check_omp_declare_reduction (r);
/*flags=*/0);
/* Instantiate members marked with attribute used. */
if (r != error_mark_node && DECL_PRESERVE_P (r))
- mark_used (r);
+ used.safe_push (r);
}
else if (TREE_CODE (r) == FIELD_DECL)
{
if (TYPE_CONTAINS_VPTR_P (type) && CLASSTYPE_KEY_METHOD (type))
vec_safe_push (keyed_classes, type);
+ /* Now that we've gone through all the members, instantiate those
+ marked with attribute used. */
+ for (tree x : used)
+ mark_used (x);
+
return type;
}
--- /dev/null
+// PR c++/97966
+// { dg-do compile { target c++11 } }
+
+template <int>
+struct S1 {
+ __attribute__((used)) S1() noexcept(noexcept(this->foo())) { }
+ void foo();
+};
+
+template <int>
+struct S2 {
+ __attribute__((used)) void bar() noexcept(noexcept(this->foo())) { }
+ void foo();
+};
+
+template <int>
+struct S3 {
+ void __attribute__((used)) bar() noexcept(noexcept(this->foo())) { }
+ void foo();
+};
+
+template <int>
+struct S4 {
+ [[gnu::used]] void bar() noexcept(noexcept(this->foo())) { }
+ void foo();
+};
+
+template <int>
+struct S5 {
+ void bar() noexcept(noexcept(this->foo())) __attribute__((used)) { }
+ void foo();
+};
+
+template <int>
+struct S6 {
+ template <int>
+ struct N {
+ [[gnu::used]] void bar() noexcept(noexcept(this->foo())) { }
+ void foo();
+ };
+};
+
+void
+g ()
+{
+ S1<1> s1;
+ S2<1> s2;
+ S3<1> s3;
+ S4<1> s4;
+ S5<1> s5;
+ S6<1>::N<1> n;
+}
+
+// Make sure that we did emit the functions marked with attribute used
+// even though they're not referenced in this TU. (Well, the S1()
+// constructor is.)
+// { dg-final { scan-assembler "_ZN2S1ILi1EEC1Ev" } }
+// { dg-final { scan-assembler "_ZN2S1ILi1EEC2Ev" } }
+// { dg-final { scan-assembler "_ZN2S2ILi1EE3barEv" } }
+// { dg-final { scan-assembler "_ZN2S3ILi1EE3barEv" } }
+// { dg-final { scan-assembler "_ZN2S4ILi1EE3barEv" } }
+// { dg-final { scan-assembler "_ZN2S5ILi1EE3barEv" } }
+// { dg-final { scan-assembler "_ZN2S6ILi1EE1NILi1EE3barEv" } }