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" } }