https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118277
--- Comment #7 from Andrew Pinski <pinskia at gcc dot gnu.org> --- static_assert does: /* Parse the message expression. */ bool string_lit = true; for (unsigned int i = 1; ; ++i) { cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, i); if (cp_parser_is_pure_string_literal (tok)) continue; else if (tok->type == CPP_CLOSE_PAREN) break; string_lit = false; break; } if (!string_lit) { location_t loc = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx26) pedwarn (loc, OPT_Wc__26_extensions, "%<static_assert%> with non-string message only " "available with %<-std=c++2c%> or %<-std=gnu++2c%>"); message = cp_parser_conditional_expression (parser); if (TREE_CODE (message) == STRING_CST) message = build1_loc (loc, PAREN_EXPR, TREE_TYPE (message), message); } else if (cxx_dialect >= cxx26) message = cp_parser_unevaluated_string_literal (parser); else message = cp_parser_string_literal (parser, /*translate=*/false, /*wide_ok=*/true); ... /* Complete the static assertion, which may mean either processing the static assert now or saving it for template instantiation. */ finish_static_assert (condition, message, assert_loc, member_p, /*show_expr_p=*/false); Inside finish_static_assert then does: cexpr_str cstr(message); if (!cstr.type_check (location)) return; /* Save the condition in case it was a concept check. */ tree orig_condition = condition; if (instantiation_dependent_expression_p (condition) || instantiation_dependent_expression_p (message)) { /* We're in a template; build a STATIC_ASSERT and put it in the right place. */ defer: tree assertion = make_node (STATIC_ASSERT); STATIC_ASSERT_CONDITION (assertion) = orig_condition; STATIC_ASSERT_MESSAGE (assertion) = cstr.message; STATIC_ASSERT_SOURCE_LOCATION (assertion) = location; if (member_p) maybe_add_class_template_decl_list (current_class_type, assertion, /*friend_p=*/0); else add_stmt (assertion); return; } ... int len; const char *msg = NULL; if (!cstr.extract (location, msg, len)) return; And finish_static_assert is called again from pt.c for STATIC_ASSERT. Notice instantiation_dependent_expression_p (message) here. So the processing of the const expr is left outside and done during semantics rather than inside the parser to handle dependent arguments and such.