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?
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