]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/reflection: fn call with splice in decltype rejected [PR124835]
authorMarek Polacek <polacek@redhat.com>
Thu, 9 Apr 2026 23:52:15 +0000 (19:52 -0400)
committerMarek Polacek <polacek@redhat.com>
Mon, 13 Apr 2026 22:19:23 +0000 (18:19 -0400)
Here we reject the valid

  decltype([:^^foo<int>:](42))

saying that a ')' is expected.  [dcl.type.decltype] says "if E is an
unparenthesized splice-expression, decltype(E) is..." and we handle it
by calling _splice_expression and setting id_expression_or_member_access_p.

But for the code above we shouldn't do this, because the [: :] isn't
the sole operand of decltype.  _nth_token_starts_splice_without_nns_p
checks that there's no :: after the :] but here we want to check that
the [: :] is followed by a ')'.

PR c++/124835

gcc/cp/ChangeLog:

* parser.cc (cp_parser_decltype_expr): Check that [: :] is
followed by a close paren before declaring it an unparenthesized
splice-expression.

gcc/testsuite/ChangeLog:

* g++.dg/reflect/decltype2.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/parser.cc
gcc/testsuite/g++.dg/reflect/decltype2.C [new file with mode: 0644]

index fe27a15a2835000112c38c06ac54ec7e83301ae9..9dbc2933e7b5c9dfbd17ccb8d6e58f6775391100 100644 (file)
@@ -19387,10 +19387,19 @@ cp_parser_decltype_expr (cp_parser *parser,
       /* [dcl.type.decltype] "if E is an unparenthesized splice-expression,
         decltype(E) is the type of the entity, object, or value designated
         by the splice-specifier of E"  */
-      if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
+      const bool unparenthesized_splice_expr_p = [&] {
+       if (!flag_reflection)
+         return false;
+       /* Skip to the end of the ':]' and see if the closing ')' follows.  */
+       saved_token_sentinel toks (parser->lexer, STS_ROLLBACK);
+       return (cp_parser_skip_entire_splice_expr (parser)
+               && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN));
+      } ();
+      if (unparenthesized_splice_expr_p)
        {
          cp_id_kind idk;
-         expr = cp_parser_splice_expression (parser, /*template_p=*/false,
+         const bool template_p = cp_parser_optional_template_keyword (parser);
+         expr = cp_parser_splice_expression (parser, template_p,
                                              /*address_p=*/false,
                                              /*template_arg_p=*/false,
                                              /*member_access_p=*/false, &idk);
diff --git a/gcc/testsuite/g++.dg/reflect/decltype2.C b/gcc/testsuite/g++.dg/reflect/decltype2.C
new file mode 100644 (file)
index 0000000..075d490
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/124835
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+template<typename T>
+constexpr T foo (T t) { return t; }
+
+template<typename T>
+struct S { };
+
+static_assert([:^^foo<int>:](42) == 42);
+static_assert(is_same_v<decltype([:^^foo<int>:]), int(int)>);
+static_assert(is_same_v<decltype([:^^foo<int>:](42)), int>);
+static_assert(is_same_v<decltype(template [:^^foo:](0)), int>);
+static_assert(is_same_v<decltype(template [:^^foo:]<int>(0)), int>);
+static_assert(is_same_v<decltype(([:^^foo<int>:])), int(&)(int)>);
+static_assert(is_same_v<decltype(([:^^foo<int>:](42))), int>);
+static_assert(is_same_v<decltype((template [:^^foo:](0))), int>);
+static_assert(is_same_v<decltype((template [:^^foo:]<int>(0))), int>);