Hi!
The following patch implements the clang::no_specializations attribute
(in all of
[[clang::no_specializations]]
[[clang::no_specializations ("reason")]]
__attribute__((no_specializations))
__attribute__((no_specializations ("reason")))
forms), which can appertain to class, variable and function templates
(though, not to their specializations), and if the attribute is
present on the template, there is an error (that is what clang++
implements, not warning) if one attempts to partially or fully
specialize it. The error can be disabled either with
-Wno-invalid-specialization on the command line
or #pragma GCC diagnostic ignored "-Winvalid-specialization" around
the specialization.
This is intended mainly for libstdc++, so that it can diagnose
various nits in the standard like
https://cplusplus.github.io/LWG/issue3990
etc.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
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.
* 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 08:56:56.485169157 +0200
+++ gcc/doc/extend.texi 2026-07-10 12:13:35.285464590 +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 08:56:56.490169091 +0200
+++ gcc/doc/invoke.texi 2026-07-10 12:10:10.070595155 +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 08:56:46.398302356 +0200
+++ gcc/c-family/c.opt 2026-07-10 09:28:31.389626692 +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-06-30 09:51:10.736130305 +0200
+++ gcc/c-family/c.opt.urls 2026-07-10 12:24:05.563224810 +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 09:13:29.716538981 +0200
+++ gcc/c-family/c-lex.cc 2026-07-10 09:28:31.389211567 +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 08:56:46.427301973 +0200
+++ gcc/cp/tree.cc 2026-07-10 09:28:31.390206197 +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 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;
/* 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)
+ else 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
necessary in all cases, but is the better default. */
--- gcc/cp/parser.cc.jj 2026-07-10 08:56:46.423302025 +0200
+++ gcc/cp/parser.cc 2026-07-10 09:28:31.396166670 +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 08:56:46.426301986 +0200
+++ gcc/cp/pt.cc 2026-07-10 10:36:24.168702936 +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,49 @@ 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)));
+ 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;
+ if (msg)
+ complained
+ = pedwarn (DECL_SOURCE_LOCATION (spec), OPT_Winvalid_specialization,
+ "%qD cannot be specialized: %qs",
+ spec, (const char *) msg);
+ else
+ complained
+ = pedwarn (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 +1135,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 +1248,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)
@@ -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);
+
return decl;
}
--- gcc/testsuite/g++.dg/ext/attr-no_specializations1.C.jj 2026-07-10
09:28:31.399823651 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations1.C 2026-07-10
11:24:51.419633855 +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
10:42:42.785701946 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations2.C 2026-07-10
11:45:51.098200141 +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
10:47:08.675213134 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations3.C 2026-07-10
11:39:02.328509858 +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
10:48:47.673914315 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations4.C 2026-07-10
11:40:40.611233219 +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
10:52:02.894353108 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations5.C 2026-07-10
11:01:02.310283329 +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
11:01:53.287619718 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations6.C 2026-07-10
11:25:35.029061958 +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
11:08:05.329776526 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations7.C 2026-07-10
11:25:47.367900147 +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
11:28:13.231987277 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations8.C 2026-07-10
11:29:18.644129459 +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
11:29:29.724984146 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations9.C 2026-07-10
11:30:05.029521162 +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
11:30:51.722908824 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations10.C 2026-07-10
11:31:22.809501153 +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
11:32:20.530744188 +0200
+++ gcc/testsuite/g++.dg/ext/attr-no_specializations11.C 2026-07-10
11:34:35.110980889 +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