Consider the following MWE: -- 8< ------------------------ template<typename T1, typename T2> struct Y { static constexpr bool value = false; }; template<> struct Y<void, void> { static constexpr bool value = true; }; template<int x> struct X { static_assert(Y<void, decltype(x)>::value, "1"); }; int main() { } -- 8< ------------------------ Compiling it with GCC 8.3, GCC 7.4, GCC 6.3, GCC 5.5, GCC 4.9.4, Clang 6.0, and Clang 7.0 gives no error (see https://www.godbolt.org/z/t8Dkw7). Compiling it with GCC 9.0 (trunk) gives an error.
This is rejected since r265789.
It is the instantiation_dependent_r hunk in pt.c that breaks this: @@ -25361,7 +25486,10 @@ return NULL_TREE; case TEMPLATE_PARM_INDEX: - return *tp; + if (dependent_type_p (TREE_TYPE (*tp))) + return *tp; + /* We'll check value-dependence separately. */ + return NULL_TREE; /* Handle expressions with type operands. */ case SIZEOF_EXPR: which got later changed to: case TEMPLATE_PARM_INDEX: if (dependent_type_p (TREE_TYPE (*tp))) return *tp; if (TEMPLATE_PARM_PARAMETER_PACK (*tp)) return *tp; /* We'll check value-dependence separately. */ return NULL_TREE; If I return *tp; unconditionally, the testcase is accepted again. This is called from: #0 instantiation_dependent_r (tp=0x7fffffffb308, walk_subtrees=0x7fffffffb23c) at ../../gcc/cp/pt.c:25945 #1 0x000000000183b7e9 in walk_tree_1 (tp=0x7fffffffb308, func=0xb1e156 <instantiation_dependent_r(tree*, int*, void*)>, data=0x0, pset=0x7fffffffb2a0, lh=0xb8e1ca <cp_walk_subtrees(tree_node**, int*, tree_node* (*)(tree_node**, int*, void*), void*, hash_set<tree_node*, default_hash_traits<tree_node*> >*)>) at ../../gcc/tree.c:12110 #2 0x000000000183cf41 in walk_tree_without_duplicates_1 (tp=0x7fffffffb308, func=0xb1e156 <instantiation_dependent_r(tree*, int*, void*)>, data=0x0, lh=0xb8e1ca <cp_walk_subtrees(tree_node**, int*, tree_node* (*)(tree_node**, int*, void*), void*, hash_set<tree_node*, default_hash_traits<tree_node*> >*)>) at ../../gcc/tree.c:12458 #3 0x0000000000b1e5e6 in instantiation_dependent_uneval_expression_p (expression=<template_parm_index 0x7fffea960210>) at ../../gcc/cp/pt.c:26042 #4 0x0000000000b7584e in finish_decltype_type (expr=<template_parm_index 0x7fffea960210>, id_expression_or_member_access_p=true, complain=3) at ../../gcc/cp/semantics.c:9363 #5 0x0000000000a5b330 in cp_parser_decltype (parser=0x7ffff7ffbab0) at ../../gcc/cp/parser.c:14688 and for finish_decltype_type nothing is asking about value-dependence I guess.
This might actually be invalid testcase with no diagnostics required though. Certainly no instantiations of X can be accepted.
My use-case is to use the instantiation of `struct X' to fire the static assert.
This needs to be verified by our C++ language lawyers, but if: "If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required." rule applies in this case, then what you are trying to do is not valid C++ and you'll need to find some other way, e.g. one where there are instantiations that could be instantiated. Say use template<typename T1, typename T2> struct Y { static constexpr bool value = false; }; template<> struct Y<void, void> { static constexpr bool value = true; }; template<> struct Y<void, float> { static constexpr bool value = true; }; template<int x, typename T, T y = 0> struct X { static_assert(Y<void, decltype(y)>::value, "1"); }; or something similar where all instantiations aren't invalid.
(In reply to Jakub Jelinek from comment #5) > This needs to be verified by our C++ language lawyers, but if: > "If no valid specialization can be generated for a template definition, and > that template is not instantiated, the template definition is ill-formed, no > diagnostic required." > rule applies in this case, then what you are trying to do is not valid C++ Right. G++ is giving a correct, though optional, diagnostic; if you want to delay this diagnostic until instantiation, you need to make the expression somehow dependent on template arguments.
The code in question, which is simplified below to match the real use-case, does not involve template specialization, and so, the quoted passage does not apply: -- 8< ----------- template<int x = 0> struct X { static_assert(sizeof(decltype(x)) == 200, "1"); }; -- 8< ----------- The said code compiles fine with other GCC and Clang versions mentioned in the initial report. The code above has the merit of not requiring the specification of a redundant/dummy template argument just to fire the static assertion.
There are indeed no explicit specializations (nor partial specializations) but IMHO the above mentioned sentence talks about all specializations, including the implicit specializations. Just read the two sentences before that, those say: "Knowing which names are type names allows the syntax of every template definition to be checked. No diagnostic shall be issued for a template definition for which a valid specialization can be generated." The example at the end of that paragraph also shows a couple of cases when issues in a template may be diagnosed even when it is not instantiated and when the diagnostics must be deferred until instantiation.
That is the C++11 wording, e.g. the C++17 wording is: "a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter" decltype(x) does not depend on the template parameter, just on its type which is known, similarly if you just used sizeof(int)==200. See also https://gcc.gnu.org/gcc-7/porting_to.html#hypothetical-instantiation https://gcc.gnu.org/gcc-8/porting_to.html#hypothetical-instantiation
Okay, I see it now. Thank you very much, Jakub, for your clear explanation.
(In reply to Tadeus Prastowo from comment #7) > The code in question, which is simplified below to match the real use-case, > does not involve template specialization, and so, the quoted passage does > not apply: As Jakub said, the rule refers to all template specializations, not just partial specializations and explicit specializations. X is a template, X<0> is a specialization of that template.
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:9944ca17c0766623bce260684edc614def7ea761 commit r13-6133-g9944ca17c0766623bce260684edc614def7ea761 Author: Jason Merrill <jason@redhat.com> Date: Fri Feb 10 16:16:45 2023 -0800 c++: static_assert (false) in template [DR2518] For a long time, people have expected to be able to write static_assert (false) in a template and only have it diagnosed if the template is instantiated, but we (and other implementations) gave an error about the uninstantiated template because the standard says that if no valid instantiation of the template is possible, the program is ill-formed, no diagnostic required, and we try to diagnose IFNDR things when feasible. At the meeting last week we were looking at CWG2518, which wanted to specify that an implementation must not accept a program containing a failing #error or static_assert. We also looked at P2593, which proposed allowing static_assert in an uninstantiated template. We ended up combining these two in order to avoid requiring implementations to reject programs with static_assert (false) in uninstantiated templates. The committee accepted this as a DR, so I'm making the change to all standard modes. This behavior was also conformant previously, since no diagnostic was required in this case. We continue to diagnose non-constant or otherwise ill-formed conditions, so no changes to existing tests were needed. DR 2518 PR c++/52809 PR c++/53638 PR c++/87389 PR c++/89741 PR c++/92099 PR c++/104041 PR c++/104691 gcc/cp/ChangeLog: * semantics.cc (finish_static_assert): Don't diagnose in template context. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2518.C: New test.