On 7/10/26 2:31 PM, Jakub Jelinek wrote:
On Fri, Jul 10, 2026 at 12:09:26PM -0400, Jason Merrill wrote:
--- gcc/doc/extend.texi.jj      2026-07-10 08:56:56.485169157 +0200
+++ gcc/doc/extend.texi 2026-07-10 12:13:35.285464590 +0200

BTW, why do your diffs omit the a/ and b/ from the filename that the output
of git show/diff/format-patch normally has?  This means that plain 'git am'
doesn't work, so anyone wanting to apply them needs to treat your patches
specially (i.e. by adding -p0).  This is only a minor inconvenience for me,
but seems like more of an issue for automatic CI.

Old habits and scripts.  Guess I could tweak the scripts to add the a/ and
b/ and drop the suffix or something.

--- gcc/cp/decl2.cc.jj  2026-07-10 08:56:46.414302144 +0200
+++ gcc/cp/decl2.cc     2026-07-10 09:28:31.390965842 +0200
@@ -1751,12 +1751,15 @@ is_late_template_attribute (tree attr, t
         if (!type)
        return true;
+      enum tree_code code = TREE_CODE (type);
+      /* Apply no_specializations even to completely unknown types.  */
+      if (is_attribute_p ("no_specializations", name))
+       return false;

I would think we want this attribute to have the same handling as these
other four attributes:

                /* But some attributes specifically apply to templates.  */
                && !is_attribute_p ("abi_tag", name)
                && !is_attribute_p ("deprecated", name)
                && !is_attribute_p ("unavailable", name)
                && !is_attribute_p ("visibility", name))

...but I guess that doesn't properly error on

+template <typename T>
+using F [[clang::no_specializations]] = T;             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }

Yeah, initially I had it next to the other 4 but this made me to move it.

So perhaps we want to check all 5 attributes before we even consider the
type, and remove the distinction between completely unknown and other
dependent types?

Handling it this way doesn't regress anything in make check-g++ and
libstdc++ testsuite.

+  auto_diagnostic_group d;
+  escaped_string msg;
+  tree args = TREE_VALUE (attr);
+  bool complained;
+  if (args)
+    msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+  auto ov = make_temp_override (global_dc->m_pedantic_errors);
+  /* Make this always an error unless -Wno-invalid-specialization.  */
+  global_dc->m_pedantic_errors = 1;

You prefer this approach to permerror_opt?

Couldn't find that, it works and guess it is better, users can
with -Wno-error=invalid-specialization downgrade it to a warning
if they wish so.

@@ -3451,6 +3497,12 @@ check_explicit_specialization (tree decl
        }
       }
+  if (decl
+      && VAR_OR_FUNCTION_DECL_P (decl)
+      && DECL_LANG_SPECIFIC (decl)
+      && DECL_TEMPLATE_SPECIALIZATION (decl))
+    maybe_diagnose_no_specializations (decl);

Why is this outside the if (...some kind of specialization...) block
immediately above?

Moving it there works too.

The following updated version passed
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26,29 make -j32 -k check-g++
and make -j32 -k check-target-libstdc++-v3.

Ok for trunk if it passes full bootstrap/regtest?

OK.

2026-07-10  Jakub Jelinek  <[email protected]>

        PR c++/120635
gcc/
        * doc/extend.texi (no_specializations): Document new
        attribute.
        * doc/invoke.texi (-Wno-invalid-specialization): Document new
        warning.
gcc/c-family/
        * c.opt (Winvalid-specialization): New option.
        * c.opt.urls: Regenerate.
        * c-lex.cc (c_common_has_attribute): Don't advertise
        gnu::no_specializations attribute availability.
gcc/cp/
        * tree.cc (cxx_gnu_attributes): Add "no_specializations" entry.
        (cxx_clang_attributes): Likewise.
        (handle_no_specializations_attribute,
        handle_gnu_no_specializations_attribute): New functions.
        * decl2.cc (is_late_template_attribute): Return false for
        "no_specializations" attribute, even on dependent types.  Don't
        differentiate between the completely unknown and dependent
        cases, for the 5 template attributes return always false, for
        others true if dependent type and false otherwise.
        * parser.cc (cp_parser_std_attribute): Use
        uneval_string_attr even for clang::no_specializations attribute.
        * pt.cc: Include "escaped_string.h".
        (maybe_diagnose_no_specializations): New function.
        (maybe_process_partial_specialization): Use it.
        (check_explicit_specialization): Likewise.
gcc/testsuite/
        * g++.dg/ext/attr-no_specializations1.C: New test.
        * g++.dg/ext/attr-no_specializations2.C: New test.
        * g++.dg/ext/attr-no_specializations3.C: New test.
        * g++.dg/ext/attr-no_specializations4.C: New test.
        * g++.dg/ext/attr-no_specializations5.C: New test.
        * g++.dg/ext/attr-no_specializations6.C: New test.
        * g++.dg/ext/attr-no_specializations7.C: New test.
        * g++.dg/ext/attr-no_specializations8.C: New test.
        * g++.dg/ext/attr-no_specializations9.C: New test.
        * g++.dg/ext/attr-no_specializations10.C: New test.
        * g++.dg/ext/attr-no_specializations11.C: New test.

--- gcc/doc/extend.texi.jj      2026-07-10 12:52:25.536004122 +0200
+++ gcc/doc/extend.texi 2026-07-10 12:58:13.546479708 +0200
@@ -31662,6 +31662,41 @@ arrays of any of the above
  @end itemize
  @end itemize
+@cindex @code{no_specializations} template attribute
+@item no_specializations
+
+The @code{no_specializations} attribute can be applied to a C++
+class template, variable template or function template, though not
+their specializations.  It instructs the compiler to error if
+such a template is explicitly specialized.  The primary use case
+for this attribute is the standard library where the standard
+specifies it is undefined behavior to specialize some template.
+The error can be disabled with @option{-Wno-invalid-specialization}
+or @code{#pragma GCC ignored "-Winvalid-specialization"}.
+
+The attribute can be specified either as @code{__attribute__
+((no_specializations))} or @code{[[clang::no_specializations]]} for 
compatibility
+with the original implementation in Clang.  To avoid portability
+complications, @code{[[gnu::no_specializations]]} is ignored with a warning.
+
+The attribute has a single optional argument, a string literal, which is
+included in the diagnostics and can provide reason why some template should
+not be specialized.
+
+@smallexample
+template <typename T>
+struct __attribute__ ((__no_specializations__)) A @{@};
+template <typename T, typename U>
+[[clang::no_specializations]] int b = 1;
+template <typename T>
+[[__clang__::__no_specializations__ ("foo cannot be specialized")]] int
+foo () @{ return 42; @}
+template <> struct A <int> @{@}; // Error
+template <typename T> int b <T, T> = 2; // Error
+template <> int foo <int> () @{ return 43; @} // Error
+@};
+@end smallexample
+
  @end table
@node Function Multiversioning
--- gcc/doc/invoke.texi.jj      2026-07-10 12:52:31.270929561 +0200
+++ gcc/doc/invoke.texi 2026-07-10 12:58:13.550479656 +0200
@@ -280,7 +280,7 @@ in the following sections.
  -Wextra-semi  -Wno-global-module  -Wno-inaccessible-base
  -Wno-inherited-variadic-ctor  -Wno-init-list-lifetime
  -Winvalid-constexpr  -Winvalid-imported-macros
--Wno-invalid-offsetof  -Wno-literal-suffix
+-Wno-invalid-offsetof  -Wno-invalid-specialization  -Wno-literal-suffix
  -Wmismatched-new-delete  -Wmismatched-tags
  -Wmultiple-inheritance  -Wnamespaces  -Wnarrowing
  -Wnoexcept  -Wnoexcept-type  -Wnon-virtual-dtor
@@ -4296,6 +4296,15 @@ compilation.  This is not enabled by def
  additional processing to determine.  It may be useful when preparing
  sets of header-units to ensure consistent macros.
+@opindex Winvalid-specialization
+@opindex Wno-invalid-specialization
+@item -Wno-invalid-specialization @r{(C++ and Objective-C++ only)}
+Do not error on explicit specializations of templates marked with the
+@code{no_specializations} attribute.  This diagnostics is enabled
+by default, and @option{-Wno-invalid-specialization} or
+@code{#pragma GCC ignored "-Winvalid-specializations"} can disable
+that diagnostics.
+
  @opindex Wliteral-suffix
  @opindex Wno-literal-suffix
  @item -Wno-literal-suffix @r{(C++ and Objective-C++ only)}
--- gcc/c-family/c.opt.jj       2026-07-10 12:52:25.525004265 +0200
+++ gcc/c-family/c.opt  2026-07-10 12:58:13.551728068 +0200
@@ -967,6 +967,10 @@ Winvalid-pch
  C ObjC C++ ObjC++ CPP(warn_invalid_pch) CppReason(CPP_W_INVALID_PCH) 
Var(cpp_warn_invalid_pch) Init(0) Warning
  Warn about PCH files that are found but not used.
+Winvalid-specialization
+C++ ObjC++ Var(warn_invalid_specialization) Init(1) Warning
+Error about specializations of templates with \"clang::no_specializations\" 
attribute.
+
  Winvalid-utf8
  C ObjC C++ ObjC++ CPP(cpp_warn_invalid_utf8) CppReason(CPP_W_INVALID_UTF8) 
Var(warn_invalid_utf8) Init(0) Warning
  Warn about invalid UTF-8 characters.
--- gcc/c-family/c.opt.urls.jj  2026-07-10 12:52:25.525004265 +0200
+++ gcc/c-family/c.opt.urls     2026-07-10 12:58:13.551969019 +0200
@@ -682,6 +682,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Option
  Winvalid-pch
  UrlSuffix(gcc/Warning-Options.html#index-Winvalid-pch)
+Winvalid-specialization
+UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Winvalid-specialization)
+
  Winvalid-utf8
  UrlSuffix(gcc/Warning-Options.html#index-Winvalid-utf8)
--- gcc/c-family/c-lex.cc.jj 2026-07-10 12:52:31.261929679 +0200
+++ gcc/c-family/c-lex.cc       2026-07-10 12:58:13.552161556 +0200
@@ -405,10 +405,12 @@ c_common_has_attribute (cpp_reader *pfil
                attr_name = NULL_TREE;
              /* gnu::trivial_abi is in the attribute table just
                 to error on it and suggest using [[clang::trivial_abi]]
-                or __attribute__((trivial_abi)).  Don't advertise it.  */
+                or __attribute__((trivial_abi)).  Don't advertise it.
+                Ditto for gnu::no_specializations.  */
              else if (c_dialect_cxx ()
                       && is_attribute_p ("gnu", attr_ns)
-                      && is_attribute_p ("trivial_abi", attr_id))
+                      && (is_attribute_p ("trivial_abi", attr_id)
+                          || is_attribute_p ("no_specializations", attr_id)))
                attr_name = NULL_TREE;
              else
                attr_name = build_tree_list (attr_ns, attr_id);
--- gcc/cp/tree.cc.jj   2026-07-10 12:52:25.533004161 +0200
+++ gcc/cp/tree.cc      2026-07-10 12:58:13.552524799 +0200
@@ -50,6 +50,10 @@ static tree handle_no_dangling_attribute
  static tree handle_annotation_attribute (tree *, tree, tree, int, bool *);
  static tree handle_trivial_abi_attribute (tree *, tree, tree, int, bool *);
  static tree handle_gnu_trivial_abi_attribute (tree *, tree, tree, int, bool 
*);
+static tree handle_no_specializations_attribute (tree *, tree, tree, int,
+                                                bool *);
+static tree handle_gnu_no_specializations_attribute (tree *, tree, tree, int,
+                                                    bool *);
/* If REF is an lvalue, returns the kind of lvalue that REF is.
     Otherwise, returns clk_none.  */
@@ -5609,6 +5613,8 @@ static const attribute_spec cxx_gnu_attr
      handle_abi_tag_attribute, NULL },
    { "no_dangling", 0, 1, false, true, false, false,
      handle_no_dangling_attribute, NULL },
+  { "no_specializations", 0, 1, false, false, false, false,
+    handle_gnu_no_specializations_attribute, NULL },
    { "trivial_abi", 0, 0, false, true, false, true,
      handle_gnu_trivial_abi_attribute, NULL },
  };
@@ -5667,6 +5673,8 @@ const scoped_attribute_specs internal_at
  // clang-format off
  static const attribute_spec cxx_clang_attributes[] =
  {
+  { "no_specializations", 0, 1, false, false, false, false,
+    handle_no_specializations_attribute, NULL },
    { "trivial_abi", 0, 0, false, true, false, true,
      handle_trivial_abi_attribute, NULL },
  };
@@ -6075,6 +6083,85 @@ has_trivial_abi_attribute (tree type)
    return lookup_attribute ("trivial_abi", TYPE_ATTRIBUTES (type));
  }
+/* Handle a "no_specializations" attribute applied via
+   [[gnu::no_specializations]].
+   We reject that spelling; suggest [[clang::no_specializations]] or
+   __attribute__((no_specializations)) instead.  */
+
+static tree
+handle_gnu_no_specializations_attribute (tree *node, tree name, tree args,
+                                        int flags, bool *no_add_attrs)
+{
+  if (flags & ATTR_FLAG_CXX11)
+    {
+      warning (OPT_Wattributes,
+              "%<[[gnu::no_specializations]]%> is not supported; use "
+              "%<[[clang::no_specializations]]%> or "
+              "%<__attribute__((no_specializations))%> instead");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  return handle_no_specializations_attribute (node, name, args, flags,
+                                             no_add_attrs);
+}
+
+/* Handle a "no_specializations" attribute.  */
+
+static tree
+handle_no_specializations_attribute (tree *node, tree name, tree args, int,
+                                    bool *no_add_attrs)
+{
+  if (args && TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+    {
+      error ("%qE attribute argument must be a string constant", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  /* Only allow on class templates, variable templates
+     and function templates.  */
+  if (!CLASS_TYPE_P (*node) && !VAR_OR_FUNCTION_DECL_P (*node))
+    {
+    invalid:
+      warning (OPT_Wattributes, "%qE attribute only applies to class, "
+                               "function or variable templates", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  tree ti = NULL_TREE;
+  if (TYPE_P (*node))
+    {
+      if (!TYPE_NAME (*node)
+         || !DECL_IMPLICIT_TYPEDEF_P (TYPE_NAME (*node))
+         || LAMBDA_TYPE_P (*node))
+       goto invalid;
+      if (TYPE_LANG_SPECIFIC (*node))
+       {
+         if (CLASSTYPE_TEMPLATE_SPECIALIZATION (*node)
+             || CLASSTYPE_EXPLICIT_INSTANTIATION (*node))
+           goto invalid;
+         ti = CLASSTYPE_TEMPLATE_INFO (*node);
+       }
+    }
+  else if (DECL_LANG_SPECIFIC (*node))
+    {
+      if (DECL_TEMPLATE_SPECIALIZATION (*node)
+         || DECL_EXPLICIT_INSTANTIATION (*node))
+       goto invalid;
+      ti = DECL_TEMPLATE_INFO (*node);
+    }
+  if (ti)
+    {
+      if (!PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
+       goto invalid;
+      if (TYPE_P (*node) && DECL_ALIAS_TEMPLATE_P (TI_TEMPLATE (ti)))
+       goto invalid;
+    }
+  else if (!processing_template_decl || !template_parm_scope_p ())
+    goto invalid;
+
+  return NULL_TREE;
+}
+
  /* Validate the trivial_abi attribute on a completed class type.
     Called from finish_struct after the class is complete.  */
--- gcc/cp/decl2.cc.jj 2026-07-10 12:52:25.526004252 +0200
+++ gcc/cp/decl2.cc     2026-07-10 19:24:05.013467480 +0200
@@ -1751,21 +1751,16 @@ is_late_template_attribute (tree attr, t
        if (!type)
        return true;
- /* We can't apply any attributes to a completely unknown type until
-        instantiation time.  */
-      enum tree_code code = TREE_CODE (type);
-      if (code == TEMPLATE_TYPE_PARM
-         || code == BOUND_TEMPLATE_TEMPLATE_PARM
-         || code == TYPENAME_TYPE)
-       return true;
-      /* Also defer most attributes on dependent types.  This is not
+      /* Some attributes specifically apply to templates.  */
+      if (is_attribute_p ("abi_tag", name)
+         || is_attribute_p ("deprecated", name)
+         || is_attribute_p ("unavailable", name)
+         || is_attribute_p ("visibility", name)
+         || is_attribute_p ("no_specializations", name))
+       return false;
+      /* Defer most attributes on dependent types.  This is not
         necessary in all cases, but is the better default.  */
-      else if (dependent_type_p (type)
-              /* But some attributes specifically apply to templates.  */
-              && !is_attribute_p ("abi_tag", name)
-              && !is_attribute_p ("deprecated", name)
-              && !is_attribute_p ("unavailable", name)
-              && !is_attribute_p ("visibility", name))
+      else if (dependent_type_p (type))
        return true;
        else
        return false;
--- gcc/cp/parser.cc.jj 2026-07-10 12:52:25.530004200 +0200
+++ gcc/cp/parser.cc    2026-07-10 12:58:13.556479579 +0200
@@ -33424,6 +33424,10 @@ cp_parser_std_attribute (cp_parser *pars
             && (is_attribute_p ("deprecated", attr_id)
                 || is_attribute_p ("nodiscard", attr_id)))
        attr_flag = uneval_string_attr;
+    else if (attr_ns
+            && is_attribute_p ("clang", attr_ns)
+            && is_attribute_p ("no_specializations", attr_id))
+      attr_flag = uneval_string_attr;
/* If this is a fake attribute created to handle -Wno-attributes,
         we must skip parsing the arguments.  */
--- gcc/cp/pt.cc.jj     2026-07-10 12:52:25.533004161 +0200
+++ gcc/cp/pt.cc        2026-07-10 19:08:06.701632050 +0200
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3.
  #include "omp-general.h"
  #include "pretty-print-markup.h"
  #include "contracts.h"
+#include "escaped_string.h"
/* The type of functions taking a tree, and some additional data, and
     returning an int.  */
@@ -1031,6 +1032,48 @@ maybe_new_partial_specialization (tree&
    return false;
  }
+/* Diagnose if SPEC is a specialization of [[clang::no_specializations]]
+   template.  */
+
+static void
+maybe_diagnose_no_specializations (tree spec)
+{
+  tree tmpl;
+  if (TREE_CODE (spec) == TYPE_DECL)
+    tmpl = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (spec));
+  else
+    tmpl = DECL_TI_TEMPLATE (spec);
+  tree t = DECL_TEMPLATE_RESULT (tmpl), attr;
+  if (TREE_CODE (t) == TYPE_DECL)
+    attr = lookup_attribute ("no_specializations",
+                            TYPE_ATTRIBUTES (TREE_TYPE (t)));
+  else
+    attr = lookup_attribute ("no_specializations", DECL_ATTRIBUTES (t));
+  if (!attr)
+    return;
+
+  auto_diagnostic_group d;
+  escaped_string msg;
+  tree args = TREE_VALUE (attr);
+  bool complained;
+  if (args)
+    msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+  if (msg)
+    complained
+      = permerror_opt (DECL_SOURCE_LOCATION (spec),
+                      OPT_Winvalid_specialization,
+                      "%qD cannot be specialized: %qs",
+                      spec, (const char *) msg);
+  else
+    complained
+      = permerror_opt (DECL_SOURCE_LOCATION (spec),
+                      OPT_Winvalid_specialization,
+                      "%qD cannot be specialized", spec);
+  if (complained)
+    inform (DECL_SOURCE_LOCATION (DECL_TEMPLATE_RESULT (tmpl)),
+           "declared %qs here", "clang::no_specializations");
+}
+
  /* The TYPE is being declared.  If it is a template type, that means it
     is a partial specialization.  Do appropriate error-checking.  */
@@ -1091,6 +1134,7 @@ maybe_process_partial_specialization (tr
            return error_mark_node;
          SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type);
          DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)) = input_location;
+         maybe_diagnose_no_specializations (TYPE_NAME (type));
          if (processing_template_decl)
            {
              tree decl = push_template_decl (TYPE_MAIN_DECL (type));
@@ -1203,6 +1247,7 @@ maybe_process_partial_specialization (tr
          DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)) = input_location;
          CLASSTYPE_TI_ARGS (type)
            = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type));
+         maybe_diagnose_no_specializations (TYPE_NAME (type));
        }
      }
    else if (processing_specialization)
@@ -3449,6 +3494,12 @@ check_explicit_specialization (tree decl
                           || DECL_DESTRUCTOR_P (decl))
                      || DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl)));
        }
+
+      if (decl
+         && VAR_OR_FUNCTION_DECL_P (decl)
+         && DECL_LANG_SPECIFIC (decl)
+         && DECL_TEMPLATE_SPECIALIZATION (decl))
+       maybe_diagnose_no_specializations (decl);
      }
return decl;
--- gcc/testsuite/g++.dg/ext/attr-no_specializations1.C.jj      2026-07-10 
12:58:13.561163871 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations1.C 2026-07-10 
12:58:13.561163871 +0200
@@ -0,0 +1,102 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename U>
+struct [[clang::no_specializations]] A {};             // { dg-message "declared 
'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[clang::no_specializations]] int b = 1;               // { dg-message "declared 
'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+[[__clang__::__no_specializations__]] int foo () { return 0; } // { dg-message 
"declared 'clang::no_specializations' here" }
+template <typename T>
+struct B {
+  struct [[clang::no_specializations]] C {};           // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] static int b;          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] int foo () { return 0; }// { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  template <typename U>
+  class [[clang::no_specializations]] D {};
+};
+A <int, long> c;
+#if __cpp_variable_templates >= 201304
+int d = b <int, long>;
+#endif
+int e = foo <int, long> ();
+template <typename T>
+struct D {};
+template <>
+struct A <int, int> { int a; };                          // { dg-error "'struct A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long, T> { long b; };                          // { dg-error "'struct A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D <T>, D <T>> { D<T> c; };                   // { dg-error "'struct A<D<T>, 
D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+int b <int, int> = 2;                                    // { dg-error "'b<int, int>' cannot 
be specialized" "" { target c++14 } }
+template <typename T>
+int b <long, T> = 3;                                     // { dg-error "'b<long int, T>' 
cannot be specialized" "" { target c++14 } }
+template <typename T>
+int b <D <T>, D <T>> = 4;                            // { dg-error "'b<D<T>, D<T> >' cannot 
be specialized" "" { target c++14 } }
+#endif
+template <>
+int foo <int, int> () { return 1; }                      // { dg-error "'int 
foo\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized" }
+struct [[clang::no_specializations]] E {};             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+using F [[clang::no_specializations]] = T;             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+[[clang::no_specializations]] int f = 1;               // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+[[clang::no_specializations]] int bar () { return 0; } // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T, typename U>
+struct G {};
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+int g = 1;
+#endif
+template <typename T, typename U>
+int baz () { return 0; }
+template <>
+struct [[clang::no_specializations]] G <int, int> { int a; };            // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct [[clang::no_specializations]] G <long, T> { long b; };            // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct [[clang::no_specializations]] G <D <T>, D <T>> { D<T> c; };     // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+#if __cpp_variable_templates >= 201304
+template <>
+[[clang::no_specializations]] int g <int, int> = 2;      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++14 } }
+template <typename T>
+[[clang::no_specializations]] int g <long, T> = 3;       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++14 } }
+template <typename T>
+[[clang::no_specializations]] int g <D <T>, D <T>> = 4;      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { 
target c++14 } }
+#endif
+template <>
+[[clang::no_specializations]] int baz <int, int> () { return 1; }        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+using H [[clang::no_specializations]] = int;           // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template struct A <double, double>;
+extern template struct A <float, float>;
+#if __cpp_variable_templates >= 201304
+template int b <double, double>;
+extern template int b <float, float>;
+#endif
+template int foo <double, double> ();
+extern template int foo <float, float> ();
+template <typename T>
+struct D2 {};
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
+template <>
+struct A <short, int> { int a; };                        // { dg-bogus "'struct A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long long, T> { long b; };                     // { dg-bogus "'struct A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D2 <T>, D2 <T>> { D2<T> c; };                        // { dg-bogus "'struct 
A<D<T>, D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <short, int> = 2;                        // { dg-bogus "'b<short, 
int>' cannot be specialized" }
+template <typename T>
+constexpr int b <long long, T> = 3;                      // { dg-bogus "'b<long long 
int, T>' cannot be specialized" }
+template <typename T>
+constexpr int b <D2 <T>, D2 <T>> = 4;                        // { dg-bogus "'b<D2<T>, 
D2<T> >' cannot be specialized" }
+#endif
+template <>
+int foo <short, int> () { return 1; }                    // { dg-bogus "'int 
foo\\\(\\\) \\\[with T = short; U = int\\\]' cannot be specialized" }
+#pragma GCC diagnostic pop
--- gcc/testsuite/g++.dg/ext/attr-no_specializations2.C.jj      2026-07-10 
12:58:13.561261240 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations2.C 2026-07-10 
12:58:13.561261240 +0200
@@ -0,0 +1,102 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename U>
+union [[clang::no_specializations ("reason1")]] A {};                        // { 
dg-message "declared 'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[__clang__::__no_specializations__ ("reason2")]] int b = 1;         // { dg-message 
"declared 'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+[[clang::no_specializations ("reason3")]] int foo () { return 0; }   // { dg-message 
"declared 'clang::no_specializations' here" }
+template <typename T>
+struct B {
+  struct [[clang::no_specializations ("reason4")]] C {};             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+  [[clang::no_specializations ("reason5")]] static int b;            // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+  [[clang::no_specializations ("reason6")]] int foo () { return 0; } // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+  template <typename U>
+  class [[clang::no_specializations ("reason7")]] D {};
+};
+A <int, long> c;
+#if __cpp_variable_templates >= 201304
+int d = b <int, long>;
+#endif
+int e = foo <int, long> ();
+template <typename T>
+struct D {};
+template <>
+union A <int, int> { int a; };                           // { dg-error "'union A<int, 
int>' cannot be specialized: 'reason1'" }
+template <typename T>
+union A <long, T> { long b; };                           // { dg-error "'union A<long 
int, T>' cannot be specialized: 'reason1'" }
+template <typename T>
+union A <D <T>, D <T>> { D<T> c; };                    // { dg-error "'union A<D<T>, 
D<T> >' cannot be specialized: 'reason1'" }
+#if __cpp_variable_templates >= 201304
+template <>
+int b <int, int> = 2;                                    // { dg-error "'b<int, int>' cannot 
be specialized: 'reason2'" "" { target c++14 } }
+template <typename T>
+int b <long, T> = 3;                                     // { dg-error "'b<long int, T>' 
cannot be specialized: 'reason2'" "" { target c++14 } }
+template <typename T>
+int b <D <T>, D <T>> = 4;                            // { dg-error "'b<D<T>, D<T> >' cannot 
be specialized: 'reason2'" "" { target c++14 } }
+#endif
+template <>
+int foo <int, int> () { return 1; }                      // { dg-error "'int 
foo\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized: 'reason3'" }
+struct [[clang::no_specializations ("reason8")]] E {};       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+template <typename T>
+using F [[clang::no_specializations ("reason9")]] = T;       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+[[clang::no_specializations ("reason10")]] int f = 1;        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+[[clang::no_specializations ("reason11")]] int bar () { return 0; } // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+template <typename T, typename U>
+union G {};
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+int g = 1;
+#endif
+template <typename T, typename U>
+int baz () { return 0; }
+template <>
+union [[clang::no_specializations ("reason12")]] G <int, int> { int a; };              
// { dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+union [[clang::no_specializations ("reason13")]] G <long, T> { long b; };              
// { dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+union [[clang::no_specializations ("reason14")]] G <D <T>, D <T>> { D<T> c; };           
    // { dg-warning "'no_specializations' attribute only applies to class, function or variable templates" }
+#if __cpp_variable_templates >= 201304
+template <>
+[[clang::no_specializations ("reason15")]] int g <int, int> = 2;       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { 
target c++14 } }
+template <typename T>
+[[clang::no_specializations ("reason16")]] int g <long, T> = 3;                // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { 
target c++14 } }
+template <typename T>
+[[clang::no_specializations ("reason17")]] int g <D <T>, D <T>> = 4;       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { target c++14 } }
+#endif
+template <>
+[[clang::no_specializations ("reason18")]] int baz <int, int> () { return 1; } // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+using H [[clang::no_specializations ("reason19")]] = int;            // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+template union A <double, double>;
+extern template union A <float, float>;
+#if __cpp_variable_templates >= 201304
+template int b <double, double>;
+extern template int b <float, float>;
+#endif
+template int foo <double, double> ();
+extern template int foo <float, float> ();
+template <typename T>
+struct D2 {};
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
+template <>
+union A <short, int> { int a; };                 // { dg-bogus "'union A<int, int>' 
cannot be specialized: 'reason1'" }
+template <typename T>
+union A <long long, T> { long b; };                      // { dg-bogus "'union A<long 
int, T>' cannot be specialized: 'reason1'" }
+template <typename T>
+union A <D2 <T>, D2 <T>> { D2<T> c; };                 // { dg-bogus "'union A<D<T>, 
D<T> >' cannot be specialized: 'reason1'" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <short, int> = 2;                        // { dg-bogus "'b<short, 
int>' cannot be specialized: 'reason2'" }
+template <typename T>
+constexpr int b <long long, T> = 3;                      // { dg-bogus "'b<long long 
int, T>' cannot be specialized: 'reason2'" }
+template <typename T>
+constexpr int b <D2 <T>, D2 <T>> = 4;                        // { dg-bogus "'b<D2<T>, 
D2<T> >' cannot be specialized: 'reason2'" }
+#endif
+template <>
+int foo <short, int> () { return 1; }                    // { dg-bogus "'int 
foo\\\(\\\) \\\[with T = short; U = int\\\]' cannot be specialized: 'reason3'" }
+#pragma GCC diagnostic pop
--- gcc/testsuite/g++.dg/ext/attr-no_specializations3.C.jj      2026-07-10 
12:58:13.561394595 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations3.C 2026-07-10 
12:58:13.561394595 +0200
@@ -0,0 +1,108 @@
+// PR c++/120635
+// { dg-do compile }
+
+template <typename T, typename U>
+struct __attribute__((no_specializations)) A {};       // { dg-message "declared 
'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+__attribute__((__no_specializations__)) int b = 1;     // { dg-message "declared 
'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+__attribute__((no_specializations)) int foo () { return 0; }   // { dg-message 
"declared 'clang::no_specializations' here" }
+template <typename T>
+struct B {
+  struct __attribute__((no_specializations)) C {};     // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  __attribute__((no_specializations)) static int b;    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  __attribute__((no_specializations)) int foo () { return 0; } // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  template <typename U>
+  class __attribute__((no_specializations)) D {};
+};
+A <int, long> c;
+#if __cpp_variable_templates >= 201304
+int d = b <int, long>;
+#endif
+int e = foo <int, long> ();
+template <typename T>
+struct D {};
+template <>
+struct A <int, int> { int a; };                          // { dg-error "'struct A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long, T> { long b; };                          // { dg-error "'struct A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D <T>, D <T> > { D<T> c; };                  // { dg-error "'struct A<D<T>, 
D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+int b <int, int> = 2;                                    // { dg-error "'b<int, int>' cannot 
be specialized" "" { target c++14 } }
+template <typename T>
+int b <long, T> = 3;                                     // { dg-error "'b<long int, T>' 
cannot be specialized" "" { target c++14 } }
+template <typename T>
+int b <D <T>, D <T>> = 4;                            // { dg-error "'b<D<T>, D<T> >' cannot 
be specialized" "" { target c++14 } }
+#endif
+template <>
+int foo <int, int> () { return 1; }                      // { dg-error "'int 
foo\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized" }
+struct __attribute__((no_specializations)) E {};       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+#if __cplusplus >= 201103
+template <typename T>
+using F __attribute__((no_specializations)) = T;       // { dg-warning "'no_specializations' 
attribute only applies to class, function or variable templates" "" { target c++11 } 
}
+#endif
+__attribute__((no_specializations)) int f = 1;         // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+__attribute__((no_specializations)) int bar () { return 0; }   // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T, typename U>
+struct G {};
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+int g = 1;
+#endif
+template <typename T, typename U>
+int baz () { return 0; }
+template <>
+struct __attribute__((no_specializations)) G <int, int> { int a; };              // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct __attribute__((no_specializations)) G <long, T> { long b; };              // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct __attribute__((no_specializations)) G <D <T>, D <T> > { D<T> c; };      // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable templates" }
+#if __cpp_variable_templates >= 201304
+template <>
+__attribute__((no_specializations)) int g <int, int> = 2;        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++14 } }
+template <typename T>
+__attribute__((no_specializations)) int g <long, T> = 3; // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++14 } }
+template <typename T>
+__attribute__((no_specializations)) int g <D <T>, D <T>> = 4;        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { 
target c++14 } }
+#endif
+template <>
+__attribute__((no_specializations)) int baz <int, int> () { return 1; }  // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+#if __cplusplus >= 201103
+template <typename T>
+using H __attribute__((no_specializations)) = int;             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++11 } }
+template struct A <double, double>;
+extern template struct A <float, float>;
+#endif
+#if __cpp_variable_templates >= 201304
+template int b <double, double>;
+extern template int b <float, float>;
+#endif
+template int foo <double, double> ();
+#if __cplusplus >= 201103
+extern template int foo <float, float> ();
+#endif
+template <typename T>
+struct D2 {};
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
+template <>
+struct A <short, int> { int a; };                        // { dg-bogus "'struct A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long long, T> { long b; };                     // { dg-bogus "'struct A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D2 <T>, D2 <T> > { D2<T> c; };               // { dg-bogus "'struct A<D<T>, 
D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <short, int> = 2;                        // { dg-bogus "'b<short, 
int>' cannot be specialized" }
+template <typename T>
+constexpr int b <long long, T> = 3;                      // { dg-bogus "'b<long long 
int, T>' cannot be specialized" }
+template <typename T>
+constexpr int b <D2 <T>, D2 <T>> = 4;                        // { dg-bogus "'b<D2<T>, 
D2<T> >' cannot be specialized" }
+#endif
+template <>
+int foo <short, int> () { return 1; }                    // { dg-bogus "'int 
foo\\\(\\\) \\\[with T = short; U = int\\\]' cannot be specialized" }
+#pragma GCC diagnostic pop
--- gcc/testsuite/g++.dg/ext/attr-no_specializations4.C.jj      2026-07-10 
12:58:13.561520825 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations4.C 2026-07-10 
12:58:13.561520825 +0200
@@ -0,0 +1,108 @@
+// PR c++/120635
+// { dg-do compile }
+
+template <typename T, typename U>
+struct __attribute__((no_specializations ("reason1"))) A {};         // { dg-message 
"declared 'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+__attribute__((__no_specializations__ ("reason2"))) int b = 1;               // { dg-message 
"declared 'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+__attribute__((no_specializations ("reason3"))) int foo () { return 0; }// { dg-message 
"declared 'clang::no_specializations' here" }
+template <typename T>
+struct B {
+  struct __attribute__((no_specializations ("reason4"))) C {};               // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+  __attribute__((no_specializations ("reason5"))) static int b;              // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+  __attribute__((no_specializations ("reason6"))) int foo () { return 0; }   // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+  template <typename U>
+  class __attribute__((no_specializations ("reason7"))) D {};
+};
+A <int, long> c;
+#if __cpp_variable_templates >= 201304
+int d = b <int, long>;
+#endif
+int e = foo <int, long> ();
+template <typename T>
+struct D {};
+template <>
+struct A <int, int> { int a; };                          // { dg-error "'struct A<int, 
int>' cannot be specialized: 'reason1'" }
+template <typename T>
+struct A <long, T> { long b; };                          // { dg-error "'struct A<long 
int, T>' cannot be specialized: 'reason1'" }
+template <typename T>
+struct A <D <T>, D <T> > { D<T> c; };                  // { dg-error "'struct A<D<T>, 
D<T> >' cannot be specialized: 'reason1'" }
+#if __cpp_variable_templates >= 201304
+template <>
+int b <int, int> = 2;                                    // { dg-error "'b<int, int>' cannot 
be specialized: 'reason2'" "" { target c++14 } }
+template <typename T>
+int b <long, T> = 3;                                     // { dg-error "'b<long int, T>' 
cannot be specialized: 'reason2'" "" { target c++14 } }
+template <typename T>
+int b <D <T>, D <T> > = 4;                           // { dg-error "'b<D<T>, D<T> >' cannot 
be specialized: 'reason2'" "" { target c++14 } }
+#endif
+template <>
+int foo <int, int> () { return 1; }                      // { dg-error "'int 
foo\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized: 'reason3'" }
+struct __attribute__((no_specializations ("reason8"))) E {}; // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+#if __cplusplus >= 201103
+template <typename T>
+using F __attribute__((no_specializations ("reason9"))) = T; // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" 
{ target c++11 } }
+#endif
+__attribute__((no_specializations ("reason10"))) int f = 1;  // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+__attribute__((no_specializations ("reason11"))) int bar () { return 0; } // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T, typename U>
+struct G {};
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+int g = 1;
+#endif
+template <typename T, typename U>
+int baz () { return 0; }
+template <>
+struct __attribute__((no_specializations ("reason12"))) G <int, int> { int a; };         
      // { dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct __attribute__((no_specializations ("reason13"))) G <long, T> { long b; };         
      // { dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct __attribute__((no_specializations ("reason14"))) G <D <T>, D <T> > { D<T> c; };   
            // { dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+#if __cpp_variable_templates >= 201304
+template <>
+__attribute__((no_specializations ("reason15"))) int g <int, int> = 2;         // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { 
target c++14 } }
+template <typename T>
+__attribute__((no_specializations ("reason16"))) int g <long, T> = 3;          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { 
target c++14 } }
+template <typename T>
+__attribute__((no_specializations ("reason17"))) int g <D <T>, D <T> > = 4;        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" "" { target c++14 } }
+#endif
+template <>
+__attribute__((no_specializations ("reason18"))) int baz <int, int> () { return 1; } // 
{ dg-warning "'no_specializations' attribute only applies to class, function or variable 
templates" }
+#if __cplusplus >= 201103
+template <typename T>
+using H __attribute__((no_specializations ("reason19"))) = int;                      // { 
dg-warning "'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++11 } }
+template struct A <double, double>;
+extern template struct A <float, float>;
+#endif
+#if __cpp_variable_templates >= 201304
+template int b <double, double>;
+extern template int b <float, float>;
+#endif
+template int foo <double, double> ();
+#if __cplusplus >= 201103
+extern template int foo <float, float> ();
+#endif
+template <typename T>
+struct D2 {};
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
+template <>
+struct A <short, int> { int a; };                        // { dg-bogus "'struct A<int, 
int>' cannot be specialized: 'reason1'" }
+template <typename T>
+struct A <long long, T> { long b; };                     // { dg-bogus "'struct A<long 
int, T>' cannot be specialized: 'reason1'" }
+template <typename T>
+struct A <D2 <T>, D2 <T> > { D2<T> c; };               // { dg-bogus "'struct A<D<T>, 
D<T> >' cannot be specialized: 'reason1'" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <short, int> = 2;                        // { dg-bogus "'b<short, 
int>' cannot be specialized: 'reason2'" }
+template <typename T>
+constexpr int b <long long, T> = 3;                      // { dg-bogus "'b<long long 
int, T>' cannot be specialized: 'reason2'" }
+template <typename T>
+constexpr int b <D2 <T>, D2 <T> > = 4;                       // { dg-bogus "'b<D2<T>, 
D2<T> >' cannot be specialized: 'reason2'" }
+#endif
+template <>
+int foo <short, int> () { return 1; }                    // { dg-bogus "'int 
foo\\\(\\\) \\\[with T = short; U = int\\\]' cannot be specialized: 'reason3'" }
+#pragma GCC diagnostic pop
--- gcc/testsuite/g++.dg/ext/attr-no_specializations5.C.jj      2026-07-10 
12:58:13.561646131 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations5.C 2026-07-10 
12:58:13.561646131 +0200
@@ -0,0 +1,160 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+
+int arr[2];
+struct S { int a, b; };
+S arr2[2];
+
+template <typename T>
+struct [[clang::no_specializations]] S1 {};
+template <typename T>
+struct [[clang::no_specializations ("foobar")]] S2 {};
+template <typename T>
+struct [[clang::no_specializations (0)]] S3 {};                        // { dg-error 
"'no_specializations' attribute argument must be a string constant|expected 
string-literal" }
+template <typename T>
+struct [[clang::no_specializations ("foo", "bar", "baz")]] S4 {};// { dg-error 
"wrong number of arguments specified for 'no_specializations' attribute" }
+template <typename T>
+struct [[clang::no_specializations (0, 1, 2)]] S5 {};          // { dg-error "wrong 
number of arguments specified for 'no_specializations' attribute|expected 
string-literal" }
+
+void
+foo (int n)
+{
+  auto a = [] [[clang::no_specializations]] () {};             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  auto b = [] constexpr [[clang::no_specializations]] {};      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+                                                               // { dg-error "parameter 
declaration before lambda declaration specifiers only optional with" "" { target 
c++20_down } .-1 }
+                                                               // { dg-error "'constexpr' 
lambda only available with" "" { target c++14_down } .-2 }
+  auto c = [] noexcept [[clang::no_specializations]] {};       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+                                                               // { dg-error "parameter 
declaration before lambda exception specification only optional with" "" { target 
c++20_down } .-1 }
+  auto d = [] () [[clang::no_specializations]] {};             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  auto e = new int [n] [[clang::no_specializations]];          // { dg-warning 
"attributes ignored on outermost array type in new expression" }
+  auto e2 = new int [n] [[clang::no_specializations]] [42];    // { dg-warning 
"attributes ignored on outermost array type in new expression" }
+  auto f = new int [n][42] [[clang::no_specializations]];      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]];                               // { dg-warning 
"attributes at the beginning of statement are ignored" }
+  [[clang::no_specializations]] {}                             // { dg-warning 
"attributes at the beginning of statement are ignored" }
+  [[clang::no_specializations]] if (true) {}                   // { dg-warning 
"attributes at the beginning of statement are ignored" }
+  [[clang::no_specializations]] while (false) {}               // { dg-warning 
"attributes at the beginning of statement are ignored" }
+  [[clang::no_specializations]] goto lab;                      // { dg-warning 
"attributes at the beginning of statement are ignored" }
+  [[clang::no_specializations]] lab:;                          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] try {} catch (int) {}          // { dg-warning 
"attributes at the beginning of statement are ignored" }
+  if ([[clang::no_specializations]] int x = 0) {}              // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  switch (n)
+    {
+    [[clang::no_specializations]] case 1:                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+    [[clang::no_specializations]] break;                       // { dg-warning 
"attributes at the beginning of statement are ignored" }
+    [[clang::no_specializations]] default:                     // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+        break;
+    }
+  for ([[clang::no_specializations]] auto a : arr) {}          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  for ([[clang::no_specializations]] auto [a, b] : arr2) {}    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+                                                               // { dg-error "structured 
bindings only available with" "" { target c++14_down } .-1 }
+  [[clang::no_specializations]] asm ("");                    // { dg-warning 
"attributes ignored on 'asm' declaration" }
+  try {} catch ([[clang::no_specializations]] int x) {}                // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  try {} catch ([[clang::no_specializations]] int) {}          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  try {} catch (int [[clang::no_specializations]] x) {}                // { dg-warning 
"attribute ignored" }
+  try {} catch (int [[clang::no_specializations]]) {}          // { dg-warning 
"attribute ignored" }
+  try {} catch (int x [[clang::no_specializations]]) {}                // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+}
+
+[[clang::no_specializations]] int bar ();                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+using foobar [[clang::no_specializations]] = int;              // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+[[clang::no_specializations]] int a;                           // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+[[clang::no_specializations]] auto [b, c] = arr;               // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+                                                               // { dg-error "structured 
bindings only available with" "" { target c++14_down } .-1 }
+[[clang::no_specializations]];                                 // { dg-warning 
"attribute ignored" }
+inline [[clang::no_specializations]] void baz () {}            // { dg-warning 
"attribute ignored" }
+                                                               // { dg-error "standard 
attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+constexpr [[clang::no_specializations]] int qux () { return 0; }// { dg-warning 
"attribute ignored" }
+                                                               // { dg-error "standard 
attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+int [[clang::no_specializations]] d;                           // { dg-warning 
"attribute ignored" }
+int const [[clang::no_specializations]] e = 1;                 // { dg-warning 
"attribute ignored" }
+struct A {} [[clang::no_specializations]];                     // { dg-warning 
"attribute ignored in declaration of 'struct A'" }
+struct A [[clang::no_specializations]];                                // { dg-warning 
"attribute ignored" }
+struct A [[clang::no_specializations]] a1;                     // { dg-warning 
"attribute ignored" }
+A [[clang::no_specializations]] a2;                            // { dg-warning 
"attribute ignored" }
+enum B { B0 } [[clang::no_specializations]];                   // { dg-warning 
"attribute ignored in declaration of 'enum B'" }
+enum B [[clang::no_specializations]];                          // { dg-warning 
"attribute ignored" }
+enum B [[clang::no_specializations]] b1;                       // { dg-warning 
"attribute ignored" }
+B [[clang::no_specializations]] b2;                            // { dg-warning 
"attribute ignored" }
+struct [[clang::no_specializations]] C {};                     // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int f [[clang::no_specializations]];                           // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int g[2] [[clang::no_specializations]];                                // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int g2 [[clang::no_specializations]] [2];                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int corge () [[clang::no_specializations]];                    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int *[[clang::no_specializations]] h;                          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int & [[clang::no_specializations]] i = f;                 // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int && [[clang::no_specializations]] j = 0;                    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" }
+int S::* [[clang::no_specializations]] k;                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+auto l = sizeof (int [2] [[clang::no_specializations]]);       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+int freddy ([[clang::no_specializations]] int a,               // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+           [[clang::no_specializations]] int,                  // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+           [[clang::no_specializations]] int c = 0,            // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+           [[clang::no_specializations]] int = 0);             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+void
+corge ([[clang::no_specializations]] int a,                    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+       [[clang::no_specializations]] int,                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+       [[clang::no_specializations]] int c = 0,                        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+       [[clang::no_specializations]] int = 0)                  // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+{
+}
+[[clang::no_specializations]] void
+garply ()                                                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+{
+}
+[[clang::no_specializations]] int
+xyzzyy ()                                                      // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+{
+  return 0;
+}
+int grault (int [[clang::no_specializations]] a,               // { dg-warning 
"attribute ignored" }
+           int [[clang::no_specializations]],                  // { dg-warning 
"attribute ignored" }
+           int [[clang::no_specializations]] c = 0,            // { dg-warning 
"attribute ignored" }
+           int [[clang::no_specializations]] = 0);             // { dg-warning 
"attribute ignored" }
+void
+waldo (int [[clang::no_specializations]] a,                    // { dg-warning 
"attribute ignored" }
+       int [[clang::no_specializations]],                      // { dg-warning 
"attribute ignored" }
+       int [[clang::no_specializations]] c = 0,                        // { dg-warning 
"attribute ignored" }
+       int [[clang::no_specializations]] = 0)                  // { dg-warning 
"attribute ignored" }
+{
+}
+int plugh (int a [[clang::no_specializations]],                        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+           int b [[clang::no_specializations]] = 0);           // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+void
+thud (int a [[clang::no_specializations]],                     // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+      int b [[clang::no_specializations]] = 0)                 // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+{
+}
+enum [[clang::no_specializations]] D { D0 };                   // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+enum class [[clang::no_specializations]] E { E0 };             // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+enum F {};
+enum [[clang::no_specializations]] F;                          // { dg-warning 
"type attributes ignored after type is already defined" }
+enum G {
+  G0 [[clang::no_specializations]],                            // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  G1 [[clang::no_specializations]] = 2                         // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+};
+namespace [[clang::no_specializations]] H { using H0 = int; }  // { dg-warning 
"'no_specializations' attribute directive ignored" }
+namespace [[clang::no_specializations]] {}                     // { dg-warning 
"'no_specializations' attribute directive ignored" }
+[[clang::no_specializations]] using namespace H;               // { dg-warning 
"'no_specializations' attribute directive ignored" }
+struct [[clang::no_specializations]] I                         // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+{
+  [[clang::no_specializations]];                               // { dg-error 
"declaration does not declare anything" }
+  [[clang::no_specializations]] int i;                         // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] int foo ();                    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] int bar () { return 1; }       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] int : 0;                       // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] int i2 : 5;                    // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  [[clang::no_specializations]] static int i3;                 // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+  static int i4;
+};
+[[clang::no_specializations]] int I::i4 = 0;                   // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+struct J : [[clang::no_specializations]] C {};                 // { dg-warning 
"attributes on base specifiers are ignored" }
+#if __cpp_concepts >= 201907L
+template <typename T>
+concept K [[clang::no_specializations]] = requires { true; };  // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable templates" 
"" { target c++20 } }
+#endif
+typedef int L [[clang::no_specializations]];                   // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+template <typename T>
+struct M {};
+template <>
+struct [[clang::no_specializations]] M<int> { int m; };          // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+typedef int N[2] [[clang::no_specializations]];                        // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
+typedef int O [[clang::no_specializations]] [2];               // { dg-warning 
"'no_specializations' attribute only applies to class, function or variable 
templates" }
--- gcc/testsuite/g++.dg/ext/attr-no_specializations6.C.jj      2026-07-10 
12:58:13.561812758 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations6.C 2026-07-10 
12:58:13.561812758 +0200
@@ -0,0 +1,75 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+// { dg-options "-Winvalid-specialization" }
+
+template <typename T, typename U>
+class [[clang::no_specializations]] A {};              // { dg-message "declared 
'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[clang::no_specializations]] constexpr int b = 1;     // { dg-message "declared 
'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+[[__clang__::__no_specializations__]] int foo () { return 0; } // { dg-message 
"declared 'clang::no_specializations' here" }
+template <typename T>
+struct D {};
+template <>
+struct A <int, int> { int a; };                          // { dg-error "'class A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long, T> { long b; };                          // { dg-error "'class A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D <T>, D <T>> { D<T> c; };                   // { dg-error "'class A<D<T>, 
D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <int, int> = 2;                          // { dg-error "'b<int, int>' cannot 
be specialized" "" { target c++14 } }
+template <typename T>
+constexpr int b <long, T> = 3;                           // { dg-error "'b<long int, T>' 
cannot be specialized" "" { target c++14 } }
+template <typename T>
+constexpr int b <D <T>, D <T>> = 4;                  // { dg-error "'b<D<T>, D<T> >' cannot 
be specialized" "" { target c++14 } }
+#endif
+template <>
+int foo <int, int> () { return 1; }                      // { dg-error "'int 
foo\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized" }
+template <typename T, typename U>
+struct [[clang::no_specializations ("this is why")]] B {}; // { dg-message 
"declared 'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[clang::no_specializations ("my other reason")]] int c = 1; // { dg-message "declared 
'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+[[__clang__::__no_specializations__ ("bar cannot be specialized")]] int bar () { return 
0; } // { dg-message "declared 'clang::no_specializations' here" }
+template <>
+struct B <int, int> { int a; };                          // { dg-error "'struct B<int, 
int>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <long, T> { long c; };                          // { dg-error "'struct B<long 
int, T>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <D <T>, D <T>> { D<T> c; };                   // { dg-error "'struct B<D<T>, 
D<T> >' cannot be specialized: 'this is why'" }
+#if __cpp_variable_templates >= 201304
+template <>
+int c <int, int> = 2;                                    // { dg-error "'c<int, int>' cannot 
be specialized: 'my other reason'" "" { target c++14 } }
+template <typename T>
+int c <long, T> = 3;                                     // { dg-error "'c<long int, T>' 
cannot be specialized: 'my other reason'" "" { target c++14 } }
+template <typename T>
+int c <D <T>, D <T>> = 4;                            // { dg-error "'c<D<T>, D<T> >' cannot 
be specialized: 'my other reason'" "" { target c++14 } }
+#endif
+template <>
+int bar <int, int> () { return 1; }                      // { dg-error "'int 
bar\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized: 'bar cannot be 
specialized'" }
+template <typename T>
+struct D2 {};
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
+template <>
+struct A <short, int> { int a; };                        // { dg-bogus "'class A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long long, T> { long b; };                     // { dg-bogus "'class A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D2 <T>, D2 <T>> { D2<T> c; };                        // { dg-bogus "'class A<D<T>, 
D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <short, int> = 2;                        // { dg-bogus "'b<short, 
int>' cannot be specialized" }
+template <typename T>
+constexpr int b <long long, T> = 3;                      // { dg-bogus "'b<long long 
int, T>' cannot be specialized" }
+template <typename T>
+constexpr int b <D2 <T>, D2 <T>> = 4;                        // { dg-bogus "'b<D2<T>, 
D2<T> >' cannot be specialized" }
+#endif
+template <>
+int foo <short, int> () { return 1; }                    // { dg-bogus "'int 
foo\\\(\\\) \\\[with T = short; U = int\\\]' cannot be specialized" }
+#pragma GCC diagnostic pop
--- gcc/testsuite/g++.dg/ext/attr-no_specializations7.C.jj      2026-07-10 
12:58:13.561926296 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations7.C 2026-07-10 
12:58:13.561926296 +0200
@@ -0,0 +1,54 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-invalid-specialization" }
+
+template <typename T, typename U>
+class [[clang::no_specializations]] A {};              // { dg-bogus "declared 
'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[clang::no_specializations]] constexpr int b = 1;     // { dg-bogus "declared 
'clang::no_specializations' here" }
+#endif
+template <typename T, typename U>
+[[__clang__::__no_specializations__]] int foo () { return 0; } // { dg-bogus 
"declared 'clang::no_specializations' here" }
+template <typename T>
+struct D {};
+template <>
+struct A <int, int> { int a; };                          // { dg-bogus "'class A<int, 
int>' cannot be specialized" }
+template <typename T>
+struct A <long, T> { long b; };                          // { dg-bogus "'class A<long 
int, T>' cannot be specialized" }
+template <typename T>
+struct A <D <T>, D <T>> { D<T> c; };                   // { dg-bogus "'class A<D<T>, 
D<T> >' cannot be specialized" }
+#if __cpp_variable_templates >= 201304
+template <>
+constexpr int b <int, int> = 2;                          // { dg-bogus "'b<int, 
int>' cannot be specialized" }
+template <typename T>
+constexpr int b <long, T> = 3;                           // { dg-bogus "'b<long int, 
T>' cannot be specialized" }
+template <typename T>
+constexpr int b <D <T>, D <T>> = 4;                  // { dg-bogus "'b<D<T>, D<T> 
>' cannot be specialized" }
+#endif
+template <>
+int foo <int, int> () { return 1; }                      // { dg-bogus "'int 
foo\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized" }
+template <typename T, typename U>
+struct [[clang::no_specializations ("this is why")]] B {}; // { dg-bogus "declared 
'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[clang::no_specializations ("my other reason")]] int c = 1; // { dg-bogus 
"declared 'clang::no_specializations' here" }
+#endif
+template <typename T, typename U>
+[[__clang__::__no_specializations__ ("bar cannot be specialized")]] int bar () { return 
0; } // { dg-bogus "declared 'clang::no_specializations' here" }
+template <>
+struct B <int, int> { int a; };                          // { dg-bogus "'struct B<int, 
int>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <long, T> { long c; };                          // { dg-bogus "'struct B<long 
int, T>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <D <T>, D <T>> { D<T> c; };                   // { dg-bogus "'struct B<D<T>, 
D<T> >' cannot be specialized: 'this is why'" }
+#if __cpp_variable_templates >= 201304
+template <>
+int c <int, int> = 2;                                    // { dg-bogus "'c<int, 
int>' cannot be specialized: 'my other reason'" }
+template <typename T>
+int c <long, T> = 3;                                     // { dg-bogus "'c<long int, 
T>' cannot be specialized: 'my other reason'" }
+template <typename T>
+int c <D <T>, D <T>> = 4;                            // { dg-bogus "'c<D<T>, D<T> 
>' cannot be specialized: 'my other reason'" }
+#endif
+template <>
+int bar <int, int> () { return 1; }                      // { dg-bogus "'int 
bar\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized: 'bar cannot be 
specialized'" }
--- gcc/testsuite/g++.dg/ext/attr-no_specializations8.C.jj      2026-07-10 
12:58:13.562029496 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations8.C 2026-07-10 
12:58:13.562029496 +0200
@@ -0,0 +1,31 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-options "-fexec-charset=IBM1047" }
+
+template <typename T, typename U>
+struct [[clang::no_specializations ("this is why")]] B {}; // { dg-message 
"declared 'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[clang::no_specializations ("my other reason")]] int c = 1; // { dg-message "declared 
'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+[[__clang__::__no_specializations__ ("bar cannot be specialized")]] int bar () { return 
0; } // { dg-message "declared 'clang::no_specializations' here" }
+template <typename T>
+struct D {};
+template <>
+struct B <int, int> { int a; };                          // { dg-error "'struct B<int, 
int>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <long, T> { long c; };                          // { dg-error "'struct B<long 
int, T>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <D <T>, D <T>> { D<T> c; };                   // { dg-error "'struct B<D<T>, 
D<T> >' cannot be specialized: 'this is why'" }
+#if __cpp_variable_templates >= 201304
+template <>
+int c <int, int> = 2;                                    // { dg-error "'c<int, int>' cannot 
be specialized: 'my other reason'" "" { target c++14 } }
+template <typename T>
+int c <long, T> = 3;                                     // { dg-error "'c<long int, T>' 
cannot be specialized: 'my other reason'" "" { target c++14 } }
+template <typename T>
+int c <D <T>, D <T>> = 4;                            // { dg-error "'c<D<T>, D<T> >' cannot 
be specialized: 'my other reason'" "" { target c++14 } }
+#endif
+template <>
+int bar <int, int> () { return 1; }                      // { dg-error "'int 
bar\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized: 'bar cannot be 
specialized'" }
--- gcc/testsuite/g++.dg/ext/attr-no_specializations9.C.jj      2026-07-10 
12:58:13.562130433 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations9.C 2026-07-10 
12:58:13.562130433 +0200
@@ -0,0 +1,31 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-options "-fexec-charset=IBM1047" }
+
+template <typename T, typename U>
+struct __attribute__((no_specializations ("this is why"))) B {}; // { dg-message 
"declared 'clang::no_specializations' here" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+__attribute__((no_specializations ("my other reason"))) int c = 1; // { dg-message "declared 
'clang::no_specializations' here" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+__attribute__((__no_specializations__ ("bar cannot be specialized"))) int bar () { 
return 0; } // { dg-message "declared 'clang::no_specializations' here" }
+template <typename T>
+struct D {};
+template <>
+struct B <int, int> { int a; };                          // { dg-error "'struct B<int, 
int>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <long, T> { long c; };                          // { dg-error "'struct B<long 
int, T>' cannot be specialized: 'this is why'" }
+template <typename T>
+struct B <D <T>, D <T>> { D<T> c; };                   // { dg-error "'struct B<D<T>, 
D<T> >' cannot be specialized: 'this is why'" }
+#if __cpp_variable_templates >= 201304
+template <>
+int c <int, int> = 2;                                    // { dg-error "'c<int, int>' cannot 
be specialized: 'my other reason'" "" { target c++14 } }
+template <typename T>
+int c <long, T> = 3;                                     // { dg-error "'c<long int, T>' 
cannot be specialized: 'my other reason'" "" { target c++14 } }
+template <typename T>
+int c <D <T>, D <T>> = 4;                            // { dg-error "'c<D<T>, D<T> >' cannot 
be specialized: 'my other reason'" "" { target c++14 } }
+#endif
+template <>
+int bar <int, int> () { return 1; }                      // { dg-error "'int 
bar\\\(\\\) \\\[with T = int; U = int\\\]' cannot be specialized: 'bar cannot be 
specialized'" }
--- gcc/testsuite/g++.dg/ext/attr-no_specializations10.C.jj     2026-07-10 
12:58:13.562226266 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations10.C        2026-07-10 
12:58:13.562226266 +0200
@@ -0,0 +1,22 @@
+// PR c++/120635
+// { dg-do preprocess { target c++11 } }
+
+#if __has_cpp_attribute (clang::no_specializations) != 1
+#error
+#endif
+#if __has_cpp_attribute (gnu::no_specializations) != 0
+#error
+#endif
+#if __has_cpp_attribute (no_specializations) != 0
+#error This fails for now
+// { dg-bogus "This fails for now" "" { xfail *-*-* } .-1 }
+#endif
+#if __has_attribute (clang::no_specializations) != 1
+#error
+#endif
+#if __has_attribute (gnu::no_specializations) != 0
+#error
+#endif
+#if __has_attribute (no_specializations) != 1
+#error
+#endif
--- gcc/testsuite/g++.dg/ext/attr-no_specializations11.C.jj     2026-07-10 
12:58:13.562324755 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations11.C        2026-07-10 
12:58:13.562324755 +0200
@@ -0,0 +1,11 @@
+// PR c++/120635
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename U>
+struct [[gnu::no_specializations]] A {};                       // { dg-warning 
"'\\\[\\\[gnu::no_specializations\\\]\\\]' is not supported; use 
'\\\[\\\[clang::no_specializations\\\]\\\]' or 
'__attribute__\\\(\\\(no_specializations\\\)\\\)' instead" }
+#if __cpp_variable_templates >= 201304
+template <typename T, typename U>
+[[gnu::no_specializations ("foo")]] int b = 1;                       // { dg-warning 
"'\\\[\\\[gnu::no_specializations\\\]\\\]' is not supported; use 
'\\\[\\\[clang::no_specializations\\\]\\\]' or '__attribute__\\\(\\\(no_specializations\\\)\\\)' 
instead" "" { target c++14 } }
+#endif
+template <typename T, typename U>
+[[__gnu__::__no_specializations__]] int foo () { return 0; }   // { dg-warning 
"'\\\[\\\[gnu::no_specializations\\\]\\\]' is not supported; use 
'\\\[\\\[clang::no_specializations\\\]\\\]' or 
'__attribute__\\\(\\\(no_specializations\\\)\\\)' instead" }


        Jakub



Reply via email to