get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2194264/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2194264,
    "url": "http://patchwork.ozlabs.org/api/patches/2194264/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/aYe6dNZ-DSgWra2i@redhat.com/",
    "project": {
        "id": 17,
        "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api",
        "name": "GNU Compiler Collection",
        "link_name": "gcc",
        "list_id": "gcc-patches.gcc.gnu.org",
        "list_email": "gcc-patches@gcc.gnu.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<aYe6dNZ-DSgWra2i@redhat.com>",
    "list_archive_url": null,
    "date": "2026-02-07T22:19:32",
    "name": "[v6] c++/reflection: splice parsing fixes [PR123823]",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "70e49545d1afc44940d6651eb6ccdae1d0cbe31d",
    "submitter": {
        "id": 14370,
        "url": "http://patchwork.ozlabs.org/api/people/14370/?format=api",
        "name": "Marek Polacek",
        "email": "polacek@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/aYe6dNZ-DSgWra2i@redhat.com/mbox/",
    "series": [
        {
            "id": 491400,
            "url": "http://patchwork.ozlabs.org/api/series/491400/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=491400",
            "date": "2026-02-07T22:19:32",
            "name": "[v6] c++/reflection: splice parsing fixes [PR123823]",
            "version": 6,
            "mbox": "http://patchwork.ozlabs.org/series/491400/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2194264/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2194264/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "gcc-patches@gcc.gnu.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "gcc-patches@gcc.gnu.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=JXszmYTk;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)",
            "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=JXszmYTk",
            "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com",
            "sourceware.org; spf=pass smtp.mailfrom=redhat.com",
            "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.129.124"
        ],
        "Received": [
            "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4f7ll66WNkz1xtr\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 08 Feb 2026 09:20:18 +1100 (AEDT)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id ABB1548F341C\n\tfor <incoming@patchwork.ozlabs.org>; Sat,  7 Feb 2026 22:20:16 +0000 (GMT)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id F3F5B48F3697\n for <gcc-patches@gcc.gnu.org>; Sat,  7 Feb 2026 22:19:39 +0000 (GMT)",
            "from mail-qv1-f69.google.com (mail-qv1-f69.google.com\n [209.85.219.69]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-349-XheyP-UTP-WKM1fsbwZ8Ng-1; Sat, 07 Feb 2026 17:19:38 -0500",
            "by mail-qv1-f69.google.com with SMTP id\n 6a1803df08f44-88a37ca7ffdso50519126d6.3\n for <gcc-patches@gcc.gnu.org>; Sat, 07 Feb 2026 14:19:38 -0800 (PST)",
            "from redhat.com ([2603:7000:9500:10::1db4])\n by smtp.gmail.com with ESMTPSA id\n af79cd13be357-8caf77f6c4fsm463034685a.7.2026.02.07.14.19.34\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sat, 07 Feb 2026 14:19:34 -0800 (PST)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org ABB1548F341C",
            "OpenDKIM Filter v2.11.0 sourceware.org F3F5B48F3697"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org F3F5B48F3697",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org F3F5B48F3697",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1770502780; cv=none;\n b=BUdL+0uQSbN6Q1iocmYgb0O1IcHgJT0W5BQmC2zdP5y0TbWZPVopJthQe4ZaUdZx84S/HbBtxyDaiGph4oW3Pf1mv1ryq8XUJ8rS6tclnVqoa/1F/GxJJmpUxLyv2IbN2guwigqhQ/1OlvzX00z4X3OvJWMz4kiCHS+bWO1aO6o=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1770502780; c=relaxed/simple;\n bh=8ZiUpS9/6ZlE4xRL8+7bo38wqsyLh0TSLTdIPFSN2ws=;\n h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version;\n b=MZy28hE7AYyxuVmYAgkKXiy3E0OnZui38ZloYR93o9ViuDC+3rxvMXHL43/UXCyLW8C7Svp75qmyNBLtLk0hzrvJvUXreN9ydGl++tvleJblBnWHDWUYfelagRib18JViBh+toeFGUeK/0WHlza5e2BjvA6gAjtefwGyEq982gU=",
        "ARC-Authentication-Results": "i=1; server2.sourceware.org",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1770502779;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=9k97Ui0I2ejVtwOviYTpH4FY/fTQ/3cAcYSb4Sl3Tdo=;\n b=JXszmYTk/XKoL8Jp+Tr11MgerimnWOQ4Mbi2cMXgy9JI0/cCwWrpDIMNJUVyu8d9r566oU\n 6xTi9fQ22kdbBhP7GXfrsM3mrrHM5nUynIhO1/RYyqjVIhSnDmtdQgtCrsDQRQCDs30pS5\n yBkLTLBi2y7K393+WYR/oipxlfwDWpo=",
        "X-MC-Unique": "XheyP-UTP-WKM1fsbwZ8Ng-1",
        "X-Mimecast-MFC-AGG-ID": "XheyP-UTP-WKM1fsbwZ8Ng_1770502777",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1770502777; x=1771107577;\n h=user-agent:in-reply-to:content-disposition:mime-version:references\n :message-id:subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=9k97Ui0I2ejVtwOviYTpH4FY/fTQ/3cAcYSb4Sl3Tdo=;\n b=l5dJhdcBEfOAHas8Yfav7uO8L6DUlrYzjuV1sYKmNePLBOYf1gY3nzW/sjr36xKgT+\n f/MrILDiWHgIuhWMaHr81rYIKY1u2y/p3rO78EF+0FJSlI1+A1wmZsMwr6QDWRCtOKcm\n WcBwjFM+sKt618vTbJMqQh9AsxsdwPR3yuspQsO4AKFyusN3F37vhgn1Atffh1zoZ3Ro\n nX6NgwXFSTEgtrFOaFh4VDMMXR7fZfDHXtkaRW21qUosuoqI19kIKZvlIAJbwgO57uKH\n /1fdQ2138MU1w1fKnu+9PA8r6ppinKANNGj47b2RyvjuypDeVWtJhpJWGD9yaH4rXKXf\n eWVg==",
        "X-Gm-Message-State": "AOJu0Yyon3LTiAFM4VTCR+r8qwSpBEHF4C5tdQae36gTwAMNZIrbNdoX\n LhepZXY1/AKj+WMqsJI+hFEzYPUrByPSoh3wg0fTiWGmDTwsm/lWF40RpBsC84u/X8ymmXYpmsy\n nRKsbKtOEmeyCw8o+KKOv6hJ9kdaK6KB1sPmbP9ZFztl5Okpw+SOy31lEc3V2hDBB5pY=",
        "X-Gm-Gg": "AZuq6aJJqJHW8nS621ZKpJrHCgzYc+14+CUs1qpKt12iObIXk2QpVp9h/vGChVn9sVN\n HemG60I1EHiUm3TqWnW1hzyTwjssA6ifWVZQn81M3jEmVEGoHQfGIb/f6/oLiKtY+Kzd6Ih3xG5\n NrXfA8P9vkeDYRQoUJfkPDK5mrYvets3nDXQDUqR9Nl0yzZN8GCffEmfGFiS+UAKCMRZfLBioHp\n knHL/U6dd0BKI2SBXaZRw7UmH73R2TfFOjA//rBlURNZIFOrs4wubHIWEaW6lPzwySycM5Qk85m\n o994gUxVv2HyA8QoeQwSbU9/KrqJ3dU2VKNsTo3CYS0xhAsGSiCiE89jQUl8nk0qWg==",
        "X-Received": [
            "by 2002:ad4:4ea1:0:b0:894:3d7d:b488 with SMTP id\n 6a1803df08f44-8953d0dee0emr97880676d6.66.1770502776322;\n Sat, 07 Feb 2026 14:19:36 -0800 (PST)",
            "by 2002:ad4:4ea1:0:b0:894:3d7d:b488 with SMTP id\n 6a1803df08f44-8953d0dee0emr97880366d6.66.1770502775200;\n Sat, 07 Feb 2026 14:19:35 -0800 (PST)"
        ],
        "Date": "Sat, 7 Feb 2026 17:19:32 -0500",
        "From": "Marek Polacek <polacek@redhat.com>",
        "To": "Jason Merrill <jason@redhat.com>",
        "Cc": "GCC Patches <gcc-patches@gcc.gnu.org>",
        "Subject": "[PATCH v6] c++/reflection: splice parsing fixes [PR123823]",
        "Message-ID": "<aYe6dNZ-DSgWra2i@redhat.com>",
        "References": "<20260128025046.1723539-1-polacek@redhat.com>\n <f9c8152d-a3e7-437d-be71-e3fe9070a294@redhat.com>\n <aXov9Pf6P1bSjaDS@redhat.com>\n <22463f02-f761-4755-a68b-cf72d8cae391@redhat.com>\n <aXv9AmLtkQMXOJKv@redhat.com>\n <a12a1ce6-9de8-4f97-b283-08c06b4a4e55@redhat.com>\n <aX-ezfDYxpwQHTUC@redhat.com>\n <66838a61-aa76-465a-bc42-71eb69b48927@redhat.com>\n <aYTzNNQ3sb6cvi-p@redhat.com>\n <329c6f94-c947-4f00-9b3f-a79f5293c388@redhat.com>",
        "MIME-Version": "1.0",
        "In-Reply-To": "<329c6f94-c947-4f00-9b3f-a79f5293c388@redhat.com>",
        "User-Agent": "Mutt/2.2.14 (2025-02-20)",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "ppmSXgW_dALGMHVXbJ5ykSjGeUQya5raSFNEHJSnhsU_1770502777",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "X-BeenThere": "gcc-patches@gcc.gnu.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>",
        "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>",
        "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>",
        "List-Post": "<mailto:gcc-patches@gcc.gnu.org>",
        "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>",
        "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>",
        "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"
    },
    "content": "On Sat, Feb 07, 2026 at 06:24:21PM +0900, Jason Merrill wrote:\n> On 2/6/26 4:44 AM, Marek Polacek wrote:\n> > On Tue, Feb 03, 2026 at 12:13:41AM +0800, Jason Merrill wrote:\n> > > On 2/2/26 2:43 AM, Marek Polacek wrote:\n> > > > On Fri, Jan 30, 2026 at 10:55:43AM +0800, Jason Merrill wrote:\n> > > > > On 1/30/26 8:36 AM, Marek Polacek wrote:\n> > > > > > On Thu, Jan 29, 2026 at 07:32:03PM +0800, Jason Merrill wrote:\n> > > > > > > On 1/28/26 11:49 PM, Marek Polacek wrote:\n> > > > > > > > On Wed, Jan 28, 2026 at 11:21:53AM +0800, Jason Merrill wrote:\n> > > > > > > > > On 1/28/26 10:50 AM, Marek Polacek wrote:\n> > > > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?\n> > > > > > > > > > \n> > > > > > > > > > -- >8 --\n> > > > > > > > > > This patch fixes the problem that when cp_parser_splice_specifier sees\n> > > > > > > > > > :]<, it always thinks it's a template-id.  Consequently, this should compile\n> > > > > > > > > > but does not:\n> > > > > > > > > > \n> > > > > > > > > >        int i;\n> > > > > > > > > >        constexpr auto r = ^^i;\n> > > > > > > > > >        bool b = [:r:] < 42;\n> > > > > > > > > > \n> > > > > > > > > > because we think that a template argument list follows the splice.\n> > > > > > > > > > Fixed by using the new cp_parser_next_token_starts_template_argument_list_p\n> > > > > > > > > > which checks that we see the whole <...>.\n> > > > > > > > > > \n> > > > > > > > > > But this turned out to be more complicated when I considered\n> > > > > > > > > > splice-specialization-specifiers in a template-argument-list.  With this\n> > > > > > > > > > patch we reject\n> > > > > > > > > > \n> > > > > > > > > >        S<[:r:] < 43> s;\n> > > > > > > > > > \n> > > > > > > > > > but I think that's fine given the footnote in [temp.names]: \"A > that\n> > > > > > > > > > encloses [...] the template-arguments of a subsequent template-id or\n> > > > > > > > > > splice-specialization-specifier, is considered nested for the purpose\n> > > > > > > > > > of this description.\"  (We can't just check !in_template_argument_list_p\n> > > > > > > > > > because [:x:]<> can be valid in a template argument list.)\n> > > > > > > > > \n> > > > > > > > > I think that's wrong under https://eel.is/c++draft/temp.names#3.1 since the\n> > > > > > > > > splice is not in a type-only context and is not preceded by template or\n> > > > > > > > > typename.\n> > > > > > > > > \n> > > > > > > > > We should accept the above and not assume that the < starts a\n> > > > > > > > > template-argument-list.  It would still be helpful to check whether it could\n> > > > > > > > > do so for -Wmissing-template-keyword.\n> > > > > > > > \n> > > > > > > > Ah, fixed (by checking template_p and typename_p).  We don't emit\n> > > > > > > > a -Wmissing-template-keyword warning but currently we say:\n> > > > > > > >       note: add 'template' to denote a template\n> > > > > > > > although this may change if we downgrade the error to a pedwarn.\n> > > > > > > > \n> > > > > > > > > > I think that cp_parser_skip_entire_template_parameter_list has a bug\n> > > > > > > > > > because it doesn't correctly handle >> in a template argument list;\n> > > > > > > > > > see the xfail in parse3.C.\n> > > > > > > > > \n> > > > > > > > > Sounds right.\n> > > > > > > > \n> > > > > > > > We have to make sure that in a template argument list we don't eat\n> > > > > > > > both > because the second > isn't spurious.  I gave it a few minutes\n> > > > > > > > but my quick fix didn't work, so I'm leaving it for later.\n> > > > > > > > \n> > > > > > > > > > I also realized that my code to detect unparenthesized splice\n> > > > > > > > > > expressions as template arguments is wrong.  [expr.prim.splice] says that\n> > > > > > > > > > \n> > > > > > > > > >        constexpr auto i = e<[:^^h:]>;\n> > > > > > > > > > \n> > > > > > > > > > is ill-formed, but I think \"S<[:r:] >= 1>\" is fine.\n> > > > > > > > > \n> > > > > > > > > Agreed, the normative citation is https://eel.is/c++draft/temp#names-6\n> > > > > > > > \n> > > > > > > > Cool, I've added that reference to a comment in the patch.\n> > > > > > > > \n> > > > > > > > > > So I moved the\n> > > > > > > > > > checking to cp_parser_template_argument while making sure that we\n> > > > > > > > > > only complain when the splice-expression is the whole template-argument.\n> > > > > > > > > \n> > > > > > > > > Sounds good.\n> > > > > > > > \n> > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?\n> > > > > > > > \n> > > > > > > > -- >8 --\n> > > > > > > > This patch fixes the problem that when cp_parser_splice_specifier sees\n> > > > > > > > :]<, it always thinks it's a template-id.  Consequently, this should compile\n> > > > > > > > but does not:\n> > > > > > > > \n> > > > > > > >       int i;\n> > > > > > > >       constexpr auto r = ^^i;\n> > > > > > > >       bool b = [:r:] < 42;\n> > > > > > > > \n> > > > > > > > because we think that a template argument list follows the splice.\n> > > > > > > > Fixed by using the new cp_parser_next_token_starts_template_argument_list_p\n> > > > > > > > which checks that we see the whole <...>.\n> > > > > > > > \n> > > > > > > > But this turned out to be more complicated when I considered\n> > > > > > > > splice-specialization-specifiers in a template-argument-list.  We should\n> > > > > > > > accept the following given [temp.names]/3:\n> > > > > > > > \n> > > > > > > >       S<[:r:] < 43> s;\n> > > > > > > > \n> > > > > > > > To that effect, I'm checking !in_template_argument_list_p along with\n> > > > > > > \n> > > > > > > I don't think that's valid either, unfortunately; even outside of a template\n> > > > > > > argument list\n> > > > > > > \n> > > > > > >      [:r:] < 42 > 0\n> > > > > > > \n> > > > > > > seems to be well-formed (though pathological) code.\n> > > > > > \n> > > > > > Oh well.  How about if I parse the template-id tentatively, and only\n> > > > > > consider the [:r:] < 42 > as a splice-specialization-specifier when\n> > > > > > the parsing worked out?\n> > > > > \n> > > > > This patch still breaks\n> > > > \n> > > > Sorry :(\n> > > > \n> > > > > using info = decltype(^^::);\n> > > > > \n> > > > > template <info R>\n> > > > > bool f()\n> > > > > {\n> > > > >     return [: R :]<42>0;\n> > > > > }\n> > > > > \n> > > > > int i;\n> > > > > int main()\n> > > > > {\n> > > > >     f<^^i>();\n> > > > > }\n> > > > > \n> > > > > We must only consider it a splice-specialization-specifier as specified by\n> > > > > [temp.names]/3.1; otherwise we should only -Wmissing-template-keyword.  And\n> > > > > I think we should share that warning code with cp_parser_id_expression.\n> > > > > \n> > > > > Well, I suppose we could also treat it as a (ill-formed)\n> > > > > splice-specialization-specifier if 'expr' is known to be a template at that\n> > > > > point, but not if it's dependent as above, and of course not if it's a\n> > > > > non-template.\n> > > > \n> > > > I've tried to do the latter.\n> > > \n> > > Ah, I wasn't thinking of them as alternatives; the latter was a refinement\n> > > of the former (an addition to [temp.names]/3.1).  That is, template_p ||\n> > > typename_p || TREE_CODE (expr) == TEMPLATE_DECL.\n> > \n> > Done.\n> > \n> > > I don't think using _next_token_starts_ here is appropriate for this case;\n> > > [temp.names] says if we have template or typename and see < it's a\n> > > template-id regardless of what follows, and I expect we can give better\n> > > syntax errors if we go ahead with that.\n> > \n> > I went back to cp_parser_nth_token_starts_template_argument_list_p.\n> \n> Once again, I think that's wrong; see below.\n\nNote that cp_parser_nth_token_starts_template_argument_list_p is\nno the one that parses the whole <>, it only checks for a <.\n\n> > > The -Wmissing-template-keyword suggestion was to avoid regressing diagnostic\n> > > quality on e.g. crash6.C.  You could also give that warning at the point of\n> > > cp_parser_simulate_error in this patch.  Without that I don't see the point\n> > > of doing the tentative parse at all, as we're just going to throw away the\n> > > result.\n> > \n> > I tried to give warnings for dependent_splice_p with missing_template_diag,\n> > but then we suggest adding 'template' where doing so would make the code\n> > ill-formed, so I removed that.  And so the crash6.C change remains.\n> > I hope that's okay.\n> \n> Yes, that's OK.\n> \n> > > And _next_token_starts_ seems redundant with tentative parsing in the\n> > > missing \"template\" case; either one or the other seems sufficient to detect\n> > > a possible template-id, both is excessive.\n> > > \n> > > I still think it would be good to share the warning code between here and\n> > > _id_expression, since they're doing the exact same thing.\n> > \n> > I think I should be able to use missing_template_diag in\n> > cp_parser_splice_expression instead of the error.  But that can\n> > hopefully wait for a different patch.\n> \n> Agreed.\n> \n> > So, how about this version?  Thanks,\n> \n> > @@ -6169,8 +6173,18 @@ cp_parser_splice_specifier (cp_parser *parser, bool template_p = false,\n> >     /* Get the reflected operand.  */\n> >     expr = splice (expr);\n> > -  /* If the next token is a '<', it's a splice-specialization-specifier.  */\n> > -  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))\n> > +  /* If the next token is a <, it could be a splice-specialization-specifier.\n> > +     But we need to handle \"[:r:] < 42\" where the < doesn't start a template\n> > +     argument list.  [temp.names]/3: A < is interpreted as the delimiter of\n> > +     a template-argument-list if either\n> > +     -- it follows a splice-specifier that either\n> > +       -- appears in a type-only context or\n> > +       -- is preceded by template or typename.  */\n> > +  if (cp_parser_nth_token_starts_template_argument_list_p (parser, 1)\n> \n> This line should not change.\n> \n> > +      /* As a courtesy to the user, if there is a < after a template\n> > +\t name, parse the construct as an s-s-s and warn about the missing\n> > +\t 'template'; it can't be anything else.  */\n> > +      && (template_p || typename_p || TREE_CODE (expr) == TEMPLATE_DECL))\n> \n> Adding this line is enough.\n\nOK, I changed that in this version.  No other changes.\n\nTested dg.exp on x86_64-pc-linux-gnu.\n\n-- >8 --\nThis patch fixes the problem that when cp_parser_splice_specifier sees\n:]<, it always thinks it's a template-id.  Consequently, this should compile\nbut does not:\n\n  int i;\n  constexpr auto r = ^^i;\n  bool b = [:r:] < 42;\n\nbecause we think that a template argument list follows the splice.\n\nFixed by implementing [temp.names]/3 better: only attempt to parse\na template argument list if we saw template or typename.  As an\nextension, also parse a template argument list if the splice yielded\na TEMPLATE_DECL -- in that case, chances are that the user simply\nforgot to specify 'template'.  In that case we'll suggest adding\n'template' in cp_parser_splice_expression.\n\nWe should accept the following given [temp.names]/3:\n\n  S<[:r:] < 43> s;\n\nand we should also accept:\n\n  [:r:] < 42 > 0;\n\nI also realized that my code to detect unparenthesized splice\nexpressions as template arguments is wrong.  [expr.prim.splice] says that\n\n  constexpr auto i = e<[:^^h:]>;\n\nis ill-formed, but \"S<[:r:] >= 1>\" is fine as per [temp.names]/6.  I moved\nthe checking to cp_parser_template_argument while making sure that we\nonly complain when the splice-expression is the whole template-argument.\n\nThis patch also fixes 123640.\n\n\tPR c++/123823\n\tPR c++/123640\n\ngcc/cp/ChangeLog:\n\n\t* parser.cc (cp_parser_splice_specifier): New typename_p parameter.\n\tCheck for typename/template/TEMPLATE_DECL before parsing a template-id.\n\t(cp_parser_splice_type_specifier): Adjust the call to\n\tcp_parser_splice_specifier.\n\t(cp_parser_splice_expression): Don't detect unparenthesized splice\n\texpressions here.  Adjust the call to cp_parser_splice_specifier.\n\t(cp_parser_splice_scope_specifier): Adjust the call to\n\tcp_parser_splice_specifier.\n\t(cp_parser_skip_entire_splice_expr): New, broken out of...\n\t(cp_parser_splice_spec_is_nns_p): ...this.\n\t(cp_parser_id_expression): Use\n\tcp_parser_next_token_starts_template_argument_list_p.\n\t(cp_parser_template_id): Call pop_deferring_access_checks.\n\t(cp_parser_template_argument): Detect unparenthesized splice\n\texpressions here.\n\t(cp_parser_next_token_starts_template_argument_list_p): New.\n\ngcc/testsuite/ChangeLog:\n\n\t* g++.dg/reflect/crash6.C: Adjust expected diagnostic.\n\t* g++.dg/reflect/expr3.C: Likewise.  Test more cases.\n\t* g++.dg/reflect/splice4.C: Adjust expected diagnostic.\n\t* g++.dg/reflect/error12.C: New test.\n\t* g++.dg/reflect/parse1.C: New test.\n\t* g++.dg/reflect/parse2.C: New test.\n\t* g++.dg/reflect/parse3.C: New test.\n\t* g++.dg/reflect/parse4.C: New test.\n\t* g++.dg/reflect/parse5.C: New test.\n\t* g++.dg/reflect/parse6.C: New test.\n---\n gcc/cp/parser.cc                       | 136 +++++++++++++++++--------\n gcc/testsuite/g++.dg/reflect/crash6.C  |   2 +-\n gcc/testsuite/g++.dg/reflect/error12.C |  22 ++++\n gcc/testsuite/g++.dg/reflect/expr3.C   |  10 +-\n gcc/testsuite/g++.dg/reflect/parse1.C  |  43 ++++++++\n gcc/testsuite/g++.dg/reflect/parse2.C  |  39 +++++++\n gcc/testsuite/g++.dg/reflect/parse3.C  |  59 +++++++++++\n gcc/testsuite/g++.dg/reflect/parse4.C  |  23 +++++\n gcc/testsuite/g++.dg/reflect/parse5.C  |  12 +++\n gcc/testsuite/g++.dg/reflect/parse6.C  |  16 +++\n gcc/testsuite/g++.dg/reflect/splice4.C |   4 +-\n 11 files changed, 320 insertions(+), 46 deletions(-)\n create mode 100644 gcc/testsuite/g++.dg/reflect/error12.C\n create mode 100644 gcc/testsuite/g++.dg/reflect/parse1.C\n create mode 100644 gcc/testsuite/g++.dg/reflect/parse2.C\n create mode 100644 gcc/testsuite/g++.dg/reflect/parse3.C\n create mode 100644 gcc/testsuite/g++.dg/reflect/parse4.C\n create mode 100644 gcc/testsuite/g++.dg/reflect/parse5.C\n create mode 100644 gcc/testsuite/g++.dg/reflect/parse6.C\n\n\nbase-commit: 1a3f27ab4d3f0d4549b0e1724d5297dc2d393a77",
    "diff": "diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc\nindex 5f1d028de0c..a65a0806f39 100644\n--- a/gcc/cp/parser.cc\n+++ b/gcc/cp/parser.cc\n@@ -3136,6 +3136,8 @@ static bool cp_parser_next_token_ends_template_argument_p\n   (cp_parser *);\n static bool cp_parser_nth_token_starts_template_argument_list_p\n   (cp_parser *, size_t);\n+static bool cp_parser_next_token_starts_template_argument_list_p\n+  (cp_parser *, cp_token ** = nullptr);\n static enum tag_types cp_parser_token_is_class_key\n   (cp_token *);\n static enum tag_types cp_parser_token_is_type_parameter_key\n@@ -6125,11 +6127,13 @@ cp_parser_next_tokens_can_start_splice_scope_spec_p (cp_parser *parser)\n       splice-specifier < template-argument-list[opt] >\n \n    TEMPLATE_P is true if we've parsed the leading template keyword.\n+   TYPENAME_P is true if we've parsed the leading typename keyword or are\n+   in a type-only context.\n    TARGS_P is set to true if there is a splice-specialization-specifier.  */\n \n static cp_expr\n cp_parser_splice_specifier (cp_parser *parser, bool template_p = false,\n-\t\t\t    bool *targs_p = nullptr)\n+\t\t\t    bool typename_p = false, bool *targs_p = nullptr)\n {\n   /* Get the location of the '[:'.  */\n   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;\n@@ -6169,8 +6173,18 @@ cp_parser_splice_specifier (cp_parser *parser, bool template_p = false,\n   /* Get the reflected operand.  */\n   expr = splice (expr);\n \n-  /* If the next token is a '<', it's a splice-specialization-specifier.  */\n-  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))\n+  /* If the next token is a <, it could be a splice-specialization-specifier.\n+     But we need to handle \"[:r:] < 42\" where the < doesn't start a template\n+     argument list.  [temp.names]/3: A < is interpreted as the delimiter of\n+     a template-argument-list if either\n+     -- it follows a splice-specifier that either\n+       -- appears in a type-only context or\n+       -- is preceded by template or typename.  */\n+  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)\n+      /* As a courtesy to the user, if there is a < after a template\n+\t name, parse the construct as an s-s-s and warn about the missing\n+\t 'template'; it can't be anything else.  */\n+      && (template_p || typename_p || TREE_CODE (expr) == TEMPLATE_DECL))\n     {\n       /* For member access splice-specialization-specifier, try to wrap\n \t non-dependent splice for function template into a BASELINK so\n@@ -6222,7 +6236,8 @@ cp_parser_splice_type_specifier (cp_parser *parser)\n   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))\n     cp_lexer_consume_token (parser->lexer);\n \n-  cp_expr expr = cp_parser_splice_specifier (parser);\n+  cp_expr expr = cp_parser_splice_specifier (parser, /*template_p=*/false,\n+\t\t\t\t\t     /*typename_p=*/true);\n   const location_t loc = (expr != error_mark_node\n \t\t\t  ? expr.get_location () : input_location);\n   tree type = expr.get_value ();\n@@ -6271,7 +6286,8 @@ cp_parser_splice_expression (cp_parser *parser, bool template_p,\n   parser->object_scope = NULL_TREE;\n   parser->qualifying_scope = NULL_TREE;\n \n-  cp_expr expr = cp_parser_splice_specifier (parser, template_p, &targs_p);\n+  cp_expr expr = cp_parser_splice_specifier (parser, template_p,\n+\t\t\t\t\t     /*typename_p=*/false, &targs_p);\n \n   /* And don't leave the scopes set, either.  */\n   parser->scope = NULL_TREE;\n@@ -6351,14 +6367,6 @@ cp_parser_splice_expression (cp_parser *parser, bool template_p,\n       return error_mark_node;\n     }\n \n-  if (parser->in_template_argument_list_p\n-      && !parser->greater_than_is_operator_p)\n-    {\n-      error_at (loc, \"unparenthesized splice expression cannot be used as \"\n-\t\t\"a template argument\");\n-      return error_mark_node;\n-    }\n-\n   /* Make sure this splice-expression produces an expression.  */\n   if (!check_splice_expr (loc, expr.get_start (), t, address_p,\n \t\t\t  member_access_p, /*complain=*/true))\n@@ -6432,7 +6440,8 @@ cp_parser_splice_scope_specifier (cp_parser *parser, bool typename_p,\n \t\t\t\t  bool template_p)\n {\n   bool targs_p = false;\n-  cp_expr scope = cp_parser_splice_specifier (parser, template_p, &targs_p);\n+  cp_expr scope = cp_parser_splice_specifier (parser, template_p, typename_p,\n+\t\t\t\t\t      &targs_p);\n   const location_t loc = scope.get_location ();\n   if (TREE_CODE (scope) == TYPE_DECL)\n     scope = TREE_TYPE (scope);\n@@ -6476,28 +6485,23 @@ cp_parser_splice_scope_specifier (cp_parser *parser, bool typename_p,\n   return scope;\n }\n \n-/* We know the next token is '[:' (optionally preceded by a template or\n-   typename) and we are wondering if a '::' follows right after the\n-   closing ':]', or after the possible '<...>' after the ':]'.  Return\n-   true if yes, false otherwise.  */\n+/* Skip the whole splice-expression: the optional typename/template,\n+   [:...:], and also the <...>, if present.  Return true if we skipped\n+   successfully.  */\n \n static bool\n-cp_parser_splice_spec_is_nns_p (cp_parser *parser)\n+cp_parser_skip_entire_splice_expr (cp_parser *parser)\n {\n-  /* ??? It'd be nice to use saved_token_sentinel, but its rollback\n-     uses cp_lexer_previous_token, but we may be the first token in the\n-     file so there are no previous tokens.  Sigh.  */\n-  cp_lexer_save_tokens (parser->lexer);\n-\n   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME)\n       || cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))\n     cp_lexer_consume_token (parser->lexer);\n \n-  bool ok = false;\n+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SPLICE))\n+    return false;\n+\n   size_t n = cp_parser_skip_balanced_tokens (parser, 1);\n   if (n != 1)\n     {\n-      ok = true;\n       /* Consume tokens up to the ':]' (including).  */\n       for (n = n - 1; n; --n)\n \tcp_lexer_consume_token (parser->lexer);\n@@ -6505,11 +6509,30 @@ cp_parser_splice_spec_is_nns_p (cp_parser *parser)\n       /* Consume the whole '<....>', if present.  */\n       if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)\n \t  && !cp_parser_skip_entire_template_parameter_list (parser))\n-\tok = false;\n+\treturn false;\n \n-      ok = ok && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE);\n+      return true;\n     }\n \n+  return false;\n+}\n+\n+/* We know the next token is '[:' (optionally preceded by a template or\n+   typename) and we are wondering if a '::' follows right after the\n+   closing ':]', or after the possible '<...>' after the ':]'.  Return\n+   true if yes, false otherwise.  */\n+\n+static bool\n+cp_parser_splice_spec_is_nns_p (cp_parser *parser)\n+{\n+  /* ??? It'd be nice to use saved_token_sentinel, but its rollback\n+     uses cp_lexer_previous_token, but we may be the first token in the\n+     file so there are no previous tokens.  Sigh.  */\n+  cp_lexer_save_tokens (parser->lexer);\n+\n+  const bool ok = (cp_parser_skip_entire_splice_expr (parser)\n+\t\t   && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE));\n+\n   /* Roll back the tokens we skipped.  */\n   cp_lexer_rollback_tokens (parser->lexer);\n \n@@ -7388,6 +7411,7 @@ cp_parser_id_expression (cp_parser *parser,\n \t\t\t\t     optional_p);\n     }\n \n+  cp_token *next;\n   if (id && TREE_CODE (id) == IDENTIFIER_NODE\n       && warn_missing_template_keyword\n       && !template_keyword_p\n@@ -7400,19 +7424,13 @@ cp_parser_id_expression (cp_parser *parser,\n       /* Don't confuse an ill-formed constructor declarator for a missing\n \t template keyword in a return type.  */\n       && !(declarator_p && constructor_name_p (id, scope))\n-      && cp_parser_nth_token_starts_template_argument_list_p (parser, 1)\n       && warning_enabled_at (token->location,\n-\t\t\t     OPT_Wmissing_template_keyword))\n-    {\n-      saved_token_sentinel toks (parser->lexer, STS_ROLLBACK);\n-      if (cp_parser_skip_entire_template_parameter_list (parser)\n-\t  /* An operator after the > suggests that the > ends a\n-\t     template-id; a name or literal suggests that the > is an\n-\t     operator.  */\n-\t  && (cp_lexer_peek_token (parser->lexer)->type\n-\t      <= CPP_LAST_PUNCTUATOR))\n-\tmissing_template_diag (token->location);\n-    }\n+\t\t\t     OPT_Wmissing_template_keyword)\n+      && cp_parser_next_token_starts_template_argument_list_p (parser, &next)\n+      /* An operator after the > suggests that the > ends a template-id;\n+\t a name or literal suggests that the > is an operator.  */\n+      && (next->type <= CPP_LAST_PUNCTUATOR))\n+    missing_template_diag (token->location);\n \n   return id;\n }\n@@ -21270,6 +21288,7 @@ cp_parser_template_id (cp_parser *parser,\n \t    error_at (token->location, \"%qT is not a template\", templ);\n \t  else\n \t    error_at (token->location, \"%qE is not a template\", templ);\n+\t  pop_deferring_access_checks ();\n \t  return error_mark_node;\n \t}\n       else\n@@ -21950,9 +21969,27 @@ cp_parser_template_argument (cp_parser* parser)\n \t  && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))\n \treturn cp_parser_braced_list (parser);\n \n+      /* [temp.names]/6: The constant-expression of a template-argument\n+\t shall not be an unparenthesized splice-expression.  */\n+      cp_token *next = nullptr;\n+      if (flag_reflection)\n+\t{\n+\t  saved_token_sentinel toks (parser->lexer, STS_ROLLBACK);\n+\t  if (cp_parser_skip_entire_splice_expr (parser))\n+\t    next = cp_lexer_peek_token (parser->lexer);\n+\t}\n+\n       /* With C++17 generalized non-type template arguments we need to handle\n \t lvalue constant expressions, too.  */\n       argument = cp_parser_assignment_expression (parser);\n+      if (UNLIKELY (cp_lexer_peek_token (parser->lexer) == next)\n+\t  && argument != error_mark_node)\n+\t{\n+\t  loc = cp_lexer_peek_token (parser->lexer)->location;\n+\t  error_at (loc, \"unparenthesized splice expression cannot be used \"\n+\t\t    \"as a template argument\");\n+\t  return error_mark_node;\n+\t}\n     }\n \n   if (!maybe_type_id)\n@@ -37987,6 +38024,25 @@ cp_parser_nth_token_starts_template_argument_list_p (cp_parser * parser,\n   return false;\n }\n \n+/* Return true if the next token is a \"<\" and we can successfully find the\n+   final \">\"; i.e., the next tokens seem like a valid template-argument-list.\n+   If NEXT is non-null, set it to the token following the \"<...>\".  */\n+\n+static bool\n+cp_parser_next_token_starts_template_argument_list_p (cp_parser *parser,\n+\t\t\t\t\t\t      cp_token **next)\n+{\n+  saved_token_sentinel toks (parser->lexer, STS_ROLLBACK);\n+  if (cp_parser_nth_token_starts_template_argument_list_p (parser, 1)\n+      && cp_parser_skip_entire_template_parameter_list (parser))\n+    {\n+      if (next)\n+\t*next = cp_lexer_peek_token (parser->lexer);\n+      return true;\n+    }\n+  return false;\n+}\n+\n /* Returns the kind of tag indicated by TOKEN, if it is a class-key,\n    or none_type otherwise.  */\n \ndiff --git a/gcc/testsuite/g++.dg/reflect/crash6.C b/gcc/testsuite/g++.dg/reflect/crash6.C\nindex 13ce48afcba..a455a61cd65 100644\n--- a/gcc/testsuite/g++.dg/reflect/crash6.C\n+++ b/gcc/testsuite/g++.dg/reflect/crash6.C\n@@ -11,7 +11,7 @@ void\n f ()\n {\n   [:R:] r; // { dg-error \"expected\" }\n-  [:R:]<int> r; // { dg-error \"reflection .\\\\\\[: R :\\\\\\]<int>. not usable in a splice expression\" }\n+  [:R:]<int> r; // { dg-error \"expected\" }\n }\n \n void\ndiff --git a/gcc/testsuite/g++.dg/reflect/error12.C b/gcc/testsuite/g++.dg/reflect/error12.C\nnew file mode 100644\nindex 00000000000..7eb787f010d\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/error12.C\n@@ -0,0 +1,22 @@\n+// PR c++/123823\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+\n+constexpr int i = 42;\n+constexpr auto r = ^^i;\n+constexpr bool b0 = template [:r:] < 0 > 0;  // { dg-error \"not a template\" }\n+constexpr bool b1 = template [:r:] < 0 < 0;  // { dg-error \"not a template|expected\" }\n+constexpr bool b2 = template [:r:] < 43;     // { dg-error \"not a template|expected\" }\n+constexpr bool b3 = template [:r:] <= 43;    // { dg-error \"template splice\" }\n+constexpr bool b4 = template [:r:] > 41;     // { dg-error \"template splice\" }\n+constexpr bool b5 = template [:r:] >= 41;    // { dg-error \"template splice\" }\n+constexpr bool b6 = template [:r:] == 42;    // { dg-error \"template splice\" }\n+constexpr bool b7 = template [:r:] != 41;    // { dg-error \"template splice\" }\n+\n+template<bool> struct S { };\n+S<template [:r:] < 43> s1;    // { dg-error \"not a template|invalid\" }\n+S<template [:r:] <= 43> s2;   // { dg-error \"template splice|invalid\" }\n+S<(template [:r:] > 41)> s3;  // { dg-error \"template splice|invalid\" }\n+S<template [:r:] >= 41> s4;   // { dg-error \"template splice|invalid\" }\n+S<template [:r:] == 42> s5;   // { dg-error \"template splice|invalid\" }\n+S<template[:r:] != 41> s6;    // { dg-error \"template splice|invalid\" }\ndiff --git a/gcc/testsuite/g++.dg/reflect/expr3.C b/gcc/testsuite/g++.dg/reflect/expr3.C\nindex 27295f1875a..de7cffe1a56 100644\n--- a/gcc/testsuite/g++.dg/reflect/expr3.C\n+++ b/gcc/testsuite/g++.dg/reflect/expr3.C\n@@ -31,15 +31,19 @@ g ()\n   int i6 = template [: ^^foo :](42);\n   int i7 = [: ^^foo<int> :](42);\n   int i8 = template [: ^^foo<int> :](42);   // { dg-error \"reflection .foo<int>. not usable in a template splice\" }\n-  int i9 = [: ^^foo :]<int>(42);\t    // { dg-error \"reflection .foo<int>. not usable in a splice expression with template arguments\" }\n+  int i9 = [: ^^foo :]<int>(42);\t    // { dg-error \"reflection .foo. not usable in a splice expression|expected\" }\n   int i10 = template [: ^^foo :]<int>(42);\n   int i11 = template [: ^^bar :]<int>(42);  // { dg-error \"no matching function for call\" }\n   int i12 = [: ^^two :]<int>;\t\t    // { dg-error \"reflection .two<int>. not usable in a splice expression with template arguments\" }\n   int i13 = template [: ^^two :]<int>;\n \n   [: ^^ST :]<int> c1;  // { dg-error \"reflection .ST<int>. not usable in a splice expression with template arguments\" }\n-  [: ^^S :]<int> c2;   // { dg-error \"not a template|reflection not usable in a splice expression with template arguments\" }\n-  [: ^^bar :]<int>();\t// { dg-error \"reflection .bar<int>. not usable in a splice expression with template arguments\" }\n+  typename [: ^^ST :]<int> c2;\n+  template [: ^^ST :]<int> c3;  // { dg-error \"expected a reflection of an expression\" }\n+  [: ^^S :]<int> c4;   // { dg-error \"expected a reflection of an expression|expected primary-expression\" }\n+  template [: ^^S :]<int> c5;   // { dg-error \".S. is not a template\" }\n+  typename [: ^^S :]<int> c6;   // { dg-error \".S. is not a template|expected\" }\n+  [: ^^bar :]<int>();\t// { dg-error \"expected\" }\n \n   auto x1 = [: ^^ST :]<int>{};\t  // { dg-error \"reflection .ST<int>. not usable in a splice expression with template arguments\" }\n   auto x2 = template [: ^^ST :]<int>{};\t// { dg-error \"expected a reflection of an expression\" }\ndiff --git a/gcc/testsuite/g++.dg/reflect/parse1.C b/gcc/testsuite/g++.dg/reflect/parse1.C\nnew file mode 100644\nindex 00000000000..e66721465cf\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/parse1.C\n@@ -0,0 +1,43 @@\n+// PR c++/123823\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+\n+constexpr int i = 42;\n+constexpr auto r = ^^i;\n+static_assert ([:r:] < 43);\n+static_assert ([:r:] <= 43);\n+static_assert ([:r:] > 41);\n+static_assert ([:r:] >= 41);\n+static_assert ([:r:] == 42);\n+static_assert ([:r:] != 41);\n+\n+static_assert (43 > [:r:]);\n+static_assert (43 >= [:r:]);\n+static_assert (41 < [:r:]);\n+static_assert (41 <= [:r:]);\n+static_assert (42 == [:r:]);\n+static_assert (41 != [:r:]);\n+\n+static_assert ([:r:] < 86 >> 1);\n+static_assert ([:r:] < 43 > 0);\n+static_assert (!([:r:] < 42 > 0));\n+\n+template<bool>\n+struct S;\n+template<>\n+struct S<true> { };\n+\n+S<[:r:] < 43> s1;\n+S<[:r:] <= 43> s2;\n+// [temp.names]/4 -> need the ().\n+S<([:r:] > 41)> s3;\n+S<[:r:] >= 41> s4;\n+S<[:r:] == 42> s5;\n+S<[:r:] != 41> s6;\n+\n+S<(43 > [:r:])> s7;\n+S<43 >= [:r:]> s8;\n+S<41 < [:r:]> s9;\n+S<41 <= [:r:]> s10;\n+S<42 == [:r:]> s11;\n+S<41 != [:r:]> s12;\ndiff --git a/gcc/testsuite/g++.dg/reflect/parse2.C b/gcc/testsuite/g++.dg/reflect/parse2.C\nnew file mode 100644\nindex 00000000000..504f87d92cc\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/parse2.C\n@@ -0,0 +1,39 @@\n+// PR c++/123640\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+\n+#include <meta>\n+\n+template<class T>\n+constexpr std::size_t field_count {\n+  std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()).size()\n+};\n+\n+template<std::size_t index, class T>\n+constexpr std::meta::info field_at {\n+  std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked())[index]\n+};\n+\n+struct S {\n+  int a, b, c;\n+  constexpr bool operator<(this auto&&l, auto&&r) noexcept\n+  {\n+    using T = std::remove_cvref_t<decltype (l)>;\n+    static constexpr auto N{field_count<T>};\n+    if constexpr (N == 0)\n+      return false;\n+    else\n+      {\n+\ttemplate for (constexpr auto i : std::make_index_sequence<N - 1>{}) // { dg-bogus \"constant\" \"\" { xfail *-*-* } }\n+\t  if (l.[:field_at<i,T>:] != r.[:field_at<i,T>:]) [[likely]]\n+\t    return l.[:field_at<i,T>:] < r.[:field_at<i,T>:];\n+\treturn l.[:field_at<N - 1, T>:] < r.[:field_at<N - 1, T>:];\n+      }\n+  }\n+};\n+\n+int\n+main ()\n+{\n+  return S{1,2,3} < S{1,3,2};\n+}\ndiff --git a/gcc/testsuite/g++.dg/reflect/parse3.C b/gcc/testsuite/g++.dg/reflect/parse3.C\nnew file mode 100644\nindex 00000000000..c114a45475b\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/parse3.C\n@@ -0,0 +1,59 @@\n+// PR c++/123823\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+\n+constexpr int i = 0;\n+constexpr auto r = ^^i;\n+\n+template<auto U, auto>\n+constexpr int S2 = [:U:];\n+\n+constexpr auto a1 = S2<[:^^r:],  // { dg-error \"unparenthesized splice\" }\n+                       [:^^r:]>; // { dg-error \"unparenthesized splice|invalid\" }\n+constexpr auto a2 = S2<([:^^r:]),\n+                       [:^^r:]>; // { dg-error \"unparenthesized splice|invalid\" }\n+constexpr auto a3 = S2<[:^^r:],  // { dg-error \"unparenthesized splice\" }\n+                       ([:^^r:])>; // { dg-error \"invalid\" }\n+constexpr auto a4 = S2<([:^^r:]),\n+                       ([:^^r:])>;\n+\n+template<int>\n+struct S { };\n+\n+template<typename>\n+struct R { };\n+\n+template<typename T>\n+constexpr int fn (T) { return 42; }\n+\n+constexpr int foo (int) { return 42; };\n+\n+S<[: ^^foo :](0)> s0;\n+S<template [: ^^fn :](1)> s1;\n+S<template [: ^^fn :](1) < 43> s2;\n+S<(template [: ^^fn :](1) > 43)> s3;\n+\n+template<int N>\n+constexpr auto var = N;\n+S<[: ^^var<1> :]> s4; // { dg-error \"unparenthesized splice|invalid\" }\n+S<([: ^^var<1> :])> s5;\n+\n+template<typename T>\n+struct C {\n+  static constexpr T t{};\n+};\n+\n+template<typename T>\n+void\n+f ()\n+{\n+  S<template [: ^^C :]<T>::t>();\n+  R<typename [: ^^C :]<int> >();\n+  R<typename [: ^^C :]<int>>();\n+}\n+\n+void\n+g ()\n+{\n+  f<int> ();\n+}\ndiff --git a/gcc/testsuite/g++.dg/reflect/parse4.C b/gcc/testsuite/g++.dg/reflect/parse4.C\nnew file mode 100644\nindex 00000000000..d4ac04f660c\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/parse4.C\n@@ -0,0 +1,23 @@\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+// From [temp.names].\n+\n+using size_t = decltype(sizeof(int));\n+using info = decltype(^^void);\n+\n+struct X {\n+  template<size_t> X* alloc();\n+  template<size_t> static X* adjust();\n+};\n+template<class T> void f(T* p) {\n+  T* p1 = p->alloc<200>();              // { dg-error \"expected\" }\n+  // { dg-warning \"expected .template. keyword before dependent template name\" \"\" { target *-*-* } .-1 }\n+  T* p2 = p->template alloc<200>();     // OK, < starts template argument list\n+  T::adjust<100>();                     // { dg-error \"expected\" }\n+  // { dg-warning \"expected .template. keyword before dependent template name\" \"\" { target *-*-* } .-1 }\n+  T::template adjust<100>();            // OK, < starts template argument list\n+\n+  static constexpr info r = ^^T::adjust;\n+  T* p3 = [:r:]<200>();                 // { dg-error \"expected\" }\n+  T* p4 = template [:r:]<200>();        // OK, < starts template argument list\n+}\ndiff --git a/gcc/testsuite/g++.dg/reflect/parse5.C b/gcc/testsuite/g++.dg/reflect/parse5.C\nnew file mode 100644\nindex 00000000000..e5386b1958c\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/parse5.C\n@@ -0,0 +1,12 @@\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+// From [temp.names].\n+\n+using info = decltype(^^void);\n+\n+template<int> struct S { };\n+constexpr int k = 5;\n+constexpr info r = ^^k;\n+S<[:r:]> s1;                        // { dg-error \"unparenthesized splice|invalid\" }\n+S<([:r:])> s2;                      // OK\n+S<[:r:] + 1> s3;                    // OK\ndiff --git a/gcc/testsuite/g++.dg/reflect/parse6.C b/gcc/testsuite/g++.dg/reflect/parse6.C\nnew file mode 100644\nindex 00000000000..ca9250f1710\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/parse6.C\n@@ -0,0 +1,16 @@\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+\n+using info = decltype(^^::);\n+\n+template <info R>\n+bool f()\n+{\n+   return [: R :]<42>0;\n+}\n+\n+int i;\n+int main()\n+{\n+   f<^^i>();\n+}\ndiff --git a/gcc/testsuite/g++.dg/reflect/splice4.C b/gcc/testsuite/g++.dg/reflect/splice4.C\nindex 29567d2df35..01ce764d665 100644\n--- a/gcc/testsuite/g++.dg/reflect/splice4.C\n+++ b/gcc/testsuite/g++.dg/reflect/splice4.C\n@@ -12,6 +12,6 @@ namespace M\n static_assert (template [: ^^M::foo :] <42> () == 42);\n static_assert (template [: members_of (^^M, std::meta::access_context::unchecked ())[0] :] <43> () == 43);\n int a = [: ^^M::foo :] <44> ();\n-// { dg-error \"reflection 'M::foo<44>' not usable in a splice expression with template arguments\" \"\" { target *-*-* } .-1 }\n+// { dg-error \"reflection 'M::foo' not usable in a splice expression|expected\" \"\" { target *-*-* } .-1 }\n int b = [: members_of (^^M, std::meta::access_context::unchecked ())[0] :] <45> ();\n-// { dg-error \"reflection 'M::foo<45>' not usable in a splice expression with template arguments\" \"\" { target *-*-* } .-1 }\n+// { dg-error \"reflection 'M::foo' not usable in a splice expression|expected\" \"\" { target *-*-* } .-1 }\n",
    "prefixes": [
        "v6"
    ]
}