On 7/10/26 10:45 AM, Jakub Jelinek wrote:
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.
--- 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.
--- 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" }
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?
+/* 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;
You prefer this approach to permerror_opt?
@@ -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?
Jason