get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 808283,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/808283/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20170831152515.GR17069@redhat.com/",
    "project": {
        "id": 17,
        "url": "http://patchwork.ozlabs.org/api/1.2/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": "<20170831152515.GR17069@redhat.com>",
    "list_archive_url": null,
    "date": "2017-08-31T15:25:15",
    "name": "C/C++ PATCH to add __remove_qualifiers (PR c/65455, c/39985)",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "6f2d166a1c0b4dc89fec80605c35dfc3e0bebe49",
    "submitter": {
        "id": 14370,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/14370/?format=api",
        "name": "Marek Polacek",
        "email": "polacek@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20170831152515.GR17069@redhat.com/mbox/",
    "series": [
        {
            "id": 856,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/856/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=856",
            "date": "2017-08-31T15:25:15",
            "name": "C/C++ PATCH to add __remove_qualifiers (PR c/65455, c/39985)",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/856/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/808283/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/808283/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<gcc-patches-return-461214-incoming=patchwork.ozlabs.org@gcc.gnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "mailing list gcc-patches@gcc.gnu.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org\n\t(client-ip=209.132.180.131; helo=sourceware.org;\n\tenvelope-from=gcc-patches-return-461214-incoming=patchwork.ozlabs.org@gcc.gnu.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org\n\theader.b=\"nGwWBV7I\"; dkim-atps=neutral",
            "sourceware.org; auth=none",
            "ext-mx01.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com",
            "ext-mx01.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=polacek@redhat.com"
        ],
        "Received": [
            "from sourceware.org (server1.sourceware.org [209.132.180.131])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xjmR833cfz9sD5\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri,  1 Sep 2017 01:25:39 +1000 (AEST)",
            "(qmail 57462 invoked by alias); 31 Aug 2017 15:25:32 -0000",
            "(qmail 57412 invoked by uid 89); 31 Aug 2017 15:25:31 -0000",
            "from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by\n\tsourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP;\n\tThu, 31 Aug 2017 15:25:21 +0000",
            "from smtp.corp.redhat.com\n\t(int-mx06.intmail.prod.int.phx2.redhat.com\n\t[10.5.11.16])\t(using TLSv1.2 with cipher AECDH-AES256-SHA\n\t(256/256 bits))\t(No client certificate requested)\tby\n\tmx1.redhat.com (Postfix) with ESMTPS id 1D71980E75;\n\tThu, 31 Aug 2017 15:25:20 +0000 (UTC)",
            "from redhat.com (ovpn-204-79.brq.redhat.com [10.40.204.79])\tby\n\tsmtp.corp.redhat.com (Postfix) with ESMTPS id 863C59ECE2;\n\tThu, 31 Aug 2017 15:25:18 +0000 (UTC)"
        ],
        "DomainKey-Signature": "a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender:date\n\t:from:to:subject:message-id:mime-version:content-type; q=dns; s=\n\tdefault; b=QLqpatbtstuGAEHyGaPDLWSjtCKxvq913NYvw9u2eJwwUmgEcbvlW\n\tLaFnC3JJlTiVxaoDB8LjKjU8W6JqKpg5kkH9dsQgDDjxEv1d4Asj8qmZhuE/9YWG\n\tuQt26qhITbpiSYADpqqieor/8ufmQz51qeoVADwqYwSuEsf2G7Gce8=",
        "DKIM-Signature": "v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender:date\n\t:from:to:subject:message-id:mime-version:content-type; s=\n\tdefault; bh=wdcZ8Cfx2TFGZsChqeKTW5ZFtek=; b=nGwWBV7I9sp6gtMEB0Vo\n\tdXo/FFz1aAWFI2ZK6VS8exIvn9/db6bCFjHhmd/xPqcmekEP/z3f5czgD2fh7kJG\n\tRgcpqmdEn6ru32LsgKbbVJy7AGhvQ6oF/nwS+SQ65yS1hofcns1xrro42PVfbyhb\n\tZZQCL1b1gL2F+xaU3z5KbLM=",
        "Mailing-List": "contact gcc-patches-help@gcc.gnu.org; run by ezmlm",
        "Precedence": "bulk",
        "List-Id": "<gcc-patches.gcc.gnu.org>",
        "List-Unsubscribe": "<mailto:gcc-patches-unsubscribe-incoming=patchwork.ozlabs.org@gcc.gnu.org>",
        "List-Archive": "<http://gcc.gnu.org/ml/gcc-patches/>",
        "List-Post": "<mailto:gcc-patches@gcc.gnu.org>",
        "List-Help": "<mailto:gcc-patches-help@gcc.gnu.org>",
        "Sender": "gcc-patches-owner@gcc.gnu.org",
        "X-Virus-Found": "No",
        "X-Spam-SWARE-Status": "No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0,\n\tGIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD,\n\tSPF_HELO_PASS autolearn=ham version=3.3.2 spammy=sk, pascal,\n\tPascal",
        "X-HELO": "mx1.redhat.com",
        "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com 1D71980E75",
        "Date": "Thu, 31 Aug 2017 17:25:15 +0200",
        "From": "Marek Polacek <polacek@redhat.com>",
        "To": "GCC Patches <gcc-patches@gcc.gnu.org>, Jason Merrill <jason@redhat.com>,\n\tJoseph Myers <joseph@codesourcery.com>",
        "Subject": "C/C++ PATCH to add __remove_qualifiers (PR c/65455, c/39985)",
        "Message-ID": "<20170831152515.GR17069@redhat.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "User-Agent": "Mutt/1.8.3 (2017-05-23)"
    },
    "content": "After a long time, I'm finally sending the revisited patch dealing with these\ntwo PRs.  To quickly recap, users were looking for a typeof variant that\nstrips type qualifiers.  I sent a path adding __typeof_noqual, but a discussion\nensued and it's been concluded that we'd rather go a different way, i.e. add\n__remove_qualifiers, which takes a typename, and strips type qualifiers.  That\nis my understanding anyway.  Here's a patch implementing just that, for both\nC and C++ FEs.\n\nHere's a link to the previous discussion:\nhttps://gcc.gnu.org/ml/gcc-patches/2017-07/msg01146.html\n\nBootstrapped/regtested on x86_64-linux, ok for trunk?\n\n2017-08-31  Marek Polacek  <polacek@redhat.com>\n\n\tPR c/39985\n\tPR c/65455\n\t* c-common.c (c_common_reswords): Add __remove_qualifiers and\n\t__remove_qualifiers__.\n\t(keyword_begins_type_specifier): Handle RID_REMOVE_QUALS.\n\t* c-common.h (enum rid): Add RID_REMOVE_QUALS.\n\n\t* c-decl.c (start_struct): Also check in_remove_qualifiers.\n\t(finish_struct): Likewise.\n\t(start_enum): Likewise.\n\t(finish_enum): Likewise.\n\t* c-parser.c (c_keyword_starts_typename): Handle RID_REMOVE_QUALS.\n\t(c_token_starts_declspecs): Likewise.\n\t(c_parser_declaration_or_fndef): For __auto_type, remove all type\n\tqualifiers.\n\t(c_parser_declspecs): Handle RID_REMOVE_QUALS.\n\t(c_parser_remove_qualifiers_specifier): New function.\n\t(c_parser_objc_selector): Handle RID_REMOVE_QUALS.\n\t* c-tree.h (enum c_typespec_kind): Update a comment.\n\tDeclare in_remove_qualifiers.\n\t* c-typeck.c (in_remove_qualifiers): New global variable.\n\t(build_external_ref): Also check in_remove_qualifiers.\n\t(struct maybe_used_decl): Likewise.\n\t(record_maybe_used_decl): Likewise.\n\t(pop_maybe_used): Likewise.\n\n\t* parser.c (cp_keyword_starts_decl_specifier_p): Handle\n\tRID_REMOVE_QUALS.\n\t(cp_parser_simple_type_specifier): Likewise.\n\t(cp_parser_sizeof_operand): For __remove_qualifiers, remove all type\n\tqualifiers.\n\n\t* doc/extend.texi: Document __remove_qualifiers.\n\n\t* c-c++-common/remove-quals-1.c: New test.\n\t* c-c++-common/remove-quals-2.c: New test.\n\t* c-c++-common/remove-quals-3.c: New test.\n\t* c-c++-common/remove-quals-4.c: New test.\n\t* g++.dg/ext/remove-quals-1.C: New test.\n\t* g++.dg/ext/remove-quals-2.C: New test.\n\t* gcc.dg/auto-type-3.c: New test.\n\t* gcc.dg/remove-quals-1.c: New test.\n\t* gcc.dg/remove-quals-2.c: New test.\n\n\n\tMarek",
    "diff": "diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c\nindex d959dbc25bb..ae92ff440f6 100644\n--- gcc/c-family/c-common.c\n+++ gcc/c-family/c-common.c\n@@ -423,6 +423,8 @@ const struct c_common_resword c_common_reswords[] =\n   { \"__null\",\t\tRID_NULL,\t0 },\n   { \"__real\",\t\tRID_REALPART,\t0 },\n   { \"__real__\",\t\tRID_REALPART,\t0 },\n+  { \"__remove_qualifiers\", RID_REMOVE_QUALS, 0 },\n+  { \"__remove_qualifiers__\", RID_REMOVE_QUALS, 0 },\n   { \"__restrict\",\tRID_RESTRICT,\t0 },\n   { \"__restrict__\",\tRID_RESTRICT,\t0 },\n   { \"__signed\",\t\tRID_SIGNED,\t0 },\n@@ -7525,6 +7527,7 @@ keyword_begins_type_specifier (enum rid keyword)\n     case RID_CLASS:\n     case RID_UNION:\n     case RID_ENUM:\n+    case RID_REMOVE_QUALS:\n       return true;\n     default:\n       if (keyword >= RID_FIRST_INT_N\ndiff --git gcc/c-family/c-common.h gcc/c-family/c-common.h\nindex 8e367680600..e726aa8844b 100644\n--- gcc/c-family/c-common.h\n+++ gcc/c-family/c-common.h\n@@ -101,7 +101,7 @@ enum rid\n   RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,\n   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,\n   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,\t     RID_BUILTIN_SHUFFLE,\n-  RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,\n+  RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,  RID_REMOVE_QUALS,\n \n   /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */\n   RID_FLOAT16,\ndiff --git gcc/c/c-decl.c gcc/c/c-decl.c\nindex d526f0e88e4..b9cd5f8cf56 100644\n--- gcc/c/c-decl.c\n+++ gcc/c/c-decl.c\n@@ -7516,12 +7516,14 @@ start_struct (location_t loc, enum tree_code code, tree name,\n      within a statement expr used within sizeof, et. al.  This is not\n      terribly serious as C++ doesn't permit statement exprs within\n      sizeof anyhow.  */\n-  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))\n+  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof\n+\t\t\t  || in_remove_qualifiers))\n     warning_at (loc, OPT_Wc___compat,\n \t\t\"defining type in %qs expression is invalid in C++\",\n-\t\t(in_sizeof\n-\t\t ? \"sizeof\"\n-\t\t : (in_typeof ? \"typeof\" : \"alignof\")));\n+\t\t(in_sizeof ? \"sizeof\"\n+\t\t : (in_typeof ? \"typeof\"\n+\t\t\t      : (in_alignof ? \"alignof\"\n+\t\t\t\t\t    : \"__remove_qualifiers\"))));\n \n   return ref;\n }\n@@ -8159,7 +8161,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,\n      struct_types.  */\n   if (warn_cxx_compat\n       && struct_parse_info != NULL\n-      && !in_sizeof && !in_typeof && !in_alignof)\n+      && !in_sizeof && !in_typeof && !in_alignof && !in_remove_qualifiers)\n     struct_parse_info->struct_types.safe_push (t);\n \n   return t;\n@@ -8235,12 +8237,14 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name)\n   /* FIXME: This will issue a warning for a use of a type defined\n      within sizeof in a statement expr.  This is not terribly serious\n      as C++ doesn't permit statement exprs within sizeof anyhow.  */\n-  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))\n+  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof\n+\t\t\t  || in_remove_qualifiers))\n     warning_at (loc, OPT_Wc___compat,\n \t\t\"defining type in %qs expression is invalid in C++\",\n-\t\t(in_sizeof\n-\t\t ? \"sizeof\"\n-\t\t : (in_typeof ? \"typeof\" : \"alignof\")));\n+\t\t(in_sizeof ? \"sizeof\"\n+\t\t : (in_typeof ? \"typeof\"\n+\t\t\t      : (in_alignof ? \"alignof\"\n+\t\t\t\t\t    : \"__remove_qualifiers\"))));\n \n   return enumtype;\n }\n@@ -8395,7 +8399,7 @@ finish_enum (tree enumtype, tree values, tree attributes)\n      struct_types.  */\n   if (warn_cxx_compat\n       && struct_parse_info != NULL\n-      && !in_sizeof && !in_typeof && !in_alignof)\n+      && !in_sizeof && !in_typeof && !in_alignof && !in_remove_qualifiers)\n     struct_parse_info->struct_types.safe_push (enumtype);\n \n   return enumtype;\ndiff --git gcc/c/c-parser.c gcc/c/c-parser.c\nindex 3d15eb7a6de..048574b0139 100644\n--- gcc/c/c-parser.c\n+++ gcc/c/c-parser.c\n@@ -504,6 +504,7 @@ c_keyword_starts_typename (enum rid keyword)\n     case RID_ACCUM:\n     case RID_SAT:\n     case RID_AUTO_TYPE:\n+    case RID_REMOVE_QUALS:\n       return true;\n     default:\n       if (keyword >= RID_FIRST_INT_N\n@@ -681,6 +682,7 @@ c_token_starts_declspecs (c_token *token)\n \tcase RID_ALIGNAS:\n \tcase RID_ATOMIC:\n \tcase RID_AUTO_TYPE:\n+\tcase RID_REMOVE_QUALS:\n \t  return true;\n \tdefault:\n \t  if (token->keyword >= RID_FIRST_INT_N\n@@ -1361,6 +1363,7 @@ static struct c_typespec c_parser_enum_specifier (c_parser *);\n static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);\n static tree c_parser_struct_declaration (c_parser *);\n static struct c_typespec c_parser_typeof_specifier (c_parser *);\n+static struct c_typespec c_parser_remove_qualifiers_specifier (c_parser *);\n static tree c_parser_alignas_specifier (c_parser *);\n static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,\n \t\t\t\t\t\t\tc_dtr_syn, bool *);\n@@ -2039,8 +2042,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,\n \t\t\t      \" initializer\");\n \t\t  init = convert_lvalue_to_rvalue (init_loc, init, true, true);\n \t\t  tree init_type = TREE_TYPE (init.value);\n-\t\t  /* As with typeof, remove all qualifiers from atomic types.  */\n-\t\t  if (init_type != error_mark_node && TYPE_ATOMIC (init_type))\n+\t\t  /* Remove all qualifiers from all types.  */\n+\t\t  if (init_type != error_mark_node)\n \t\t    init_type\n \t\t      = c_build_qualified_type (init_type, TYPE_UNQUALIFIED);\n \t\t  bool vm_type = variably_modified_type_p (init_type,\n@@ -2732,6 +2735,14 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,\n \t  t = c_parser_typeof_specifier (parser);\n \t  declspecs_add_type (loc, specs, t);\n \t  break;\n+\tcase RID_REMOVE_QUALS:\n+\t  if (!typespec_ok)\n+\t    goto out;\n+\t  attrs_ok = true;\n+\t  seen_type = true;\n+\t  t = c_parser_remove_qualifiers_specifier (parser);\n+\t  declspecs_add_type (loc, specs, t);\n+\t  break;\n \tcase RID_ATOMIC:\n \t  /* C parser handling of Objective-C constructs needs\n \t     checking for correct lvalue-to-rvalue conversions, and\n@@ -3435,6 +3446,55 @@ c_parser_typeof_specifier (c_parser *parser)\n   return ret;\n }\n \n+/* Parse a __remove_qualifiers specifier (a GNU extension).\n+\n+   remove-qualifiers-specifier:\n+     __remove_qualifiers ( type-name )\n+*/\n+\n+static struct c_typespec\n+c_parser_remove_qualifiers_specifier (c_parser *parser)\n+{\n+  struct c_typespec ret;\n+  ret.kind = ctsk_typeof;\n+  ret.spec = error_mark_node;\n+  ret.expr = NULL_TREE;\n+  ret.expr_const_operands = true;\n+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_REMOVE_QUALS));\n+\n+  /* Consume '__remove_qualifiers'.  */\n+  c_parser_consume_token (parser);\n+\n+  matching_parens parens;\n+  if (!parens.require_open (parser))\n+    return ret;\n+\n+  /* Only accept a type-name as an argument.  */\n+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))\n+    {\n+      /* Do not warn about problems with the expression.  */\n+      c_inhibit_evaluation_warnings++;\n+      in_remove_qualifiers++;\n+      struct c_type_name *type = c_parser_type_name (parser);\n+      /* Go back to evaluating expressions.  */\n+      c_inhibit_evaluation_warnings--;\n+      in_remove_qualifiers--;\n+      if (type != NULL)\n+\t{\n+\t  ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands);\n+\t  pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));\n+\t  /* Remove all type qualifiers.  */\n+\t  if (ret.spec != error_mark_node)\n+\t    ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED);\n+\t}\n+    }\n+  else\n+    error_at (c_parser_peek_token (parser)->location,\n+\t      \"%<__remove_qualifiers%> can only be applied to a type\");\n+  parens.skip_until_found_close (parser);\n+  return ret;\n+}\n+\n /* Parse an alignment-specifier.\n \n    C11 6.7.5:\n@@ -9879,7 +9939,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)\n        break continue return goto asm sizeof typeof __alignof\n        unsigned long const short volatile signed restrict _Complex\n        in out inout bycopy byref oneway int char float double void _Bool\n-       _Atomic\n+       _Atomic __remove_qualifiers\n \n    ??? Why this selection of keywords but not, for example, storage\n    class specifiers?  */\n@@ -9944,6 +10004,7 @@ c_parser_objc_selector (c_parser *parser)\n     case RID_INT_N_1:\n     case RID_INT_N_2:\n     case RID_INT_N_3:\n+    case RID_REMOVE_QUALS:\n       c_parser_consume_token (parser);\n       return value;\n     default:\ndiff --git gcc/c/c-tree.h gcc/c/c-tree.h\nindex 96c7ae7613f..e16c4185350 100644\n--- gcc/c/c-tree.h\n+++ gcc/c/c-tree.h\n@@ -191,7 +191,7 @@ enum c_typespec_kind {\n   ctsk_typedef,\n   /* An ObjC-specific kind of type specifier.  */\n   ctsk_objc,\n-  /* A typeof specifier, or _Atomic ( type-name ).  */\n+  /* A typeof specifier, _Atomic ( type-name ), or __remove_qualifiers.  */\n   ctsk_typeof\n };\n \n@@ -617,6 +617,7 @@ extern bool c_vla_unspec_p (tree x, tree fn);\n extern int in_alignof;\n extern int in_sizeof;\n extern int in_typeof;\n+extern int in_remove_qualifiers;\n \n extern tree c_last_sizeof_arg;\n extern location_t c_last_sizeof_loc;\ndiff --git gcc/c/c-typeck.c gcc/c/c-typeck.c\nindex 135dd9d665c..ce720802e70 100644\n--- gcc/c/c-typeck.c\n+++ gcc/c/c-typeck.c\n@@ -72,6 +72,9 @@ int in_sizeof;\n /* The level of nesting inside \"typeof\".  */\n int in_typeof;\n \n+/* The level of nesting inside \"__remove_qualifiers\".  */\n+int in_remove_qualifiers;\n+\n /* The argument of last parsed sizeof expression, only to be tested\n    if expr.original_code == SIZEOF_EXPR.  */\n tree c_last_sizeof_arg;\n@@ -2782,7 +2785,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)\n \n   if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)\n     {\n-      if (!in_sizeof && !in_typeof)\n+      if (!in_sizeof && !in_typeof && !in_remove_qualifiers)\n \tC_DECL_USED (ref) = 1;\n       else if (DECL_INITIAL (ref) == NULL_TREE\n \t       && DECL_EXTERNAL (ref)\n@@ -2838,7 +2841,7 @@ struct maybe_used_decl\n {\n   /* The decl.  */\n   tree decl;\n-  /* The level seen at (in_sizeof + in_typeof).  */\n+  /* The level seen at (in_sizeof + in_typeof + in_remove_qualifiers).  */\n   int level;\n   /* The next one at this level or above, or NULL.  */\n   struct maybe_used_decl *next;\n@@ -2856,7 +2859,7 @@ record_maybe_used_decl (tree decl)\n {\n   struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);\n   t->decl = decl;\n-  t->level = in_sizeof + in_typeof;\n+  t->level = in_sizeof + in_typeof + in_remove_qualifiers;\n   t->next = maybe_used_decls;\n   maybe_used_decls = t;\n }\n@@ -2870,7 +2873,7 @@ void\n pop_maybe_used (bool used)\n {\n   struct maybe_used_decl *p = maybe_used_decls;\n-  int cur_level = in_sizeof + in_typeof;\n+  int cur_level = in_sizeof + in_typeof + in_remove_qualifiers;\n   while (p && p->level > cur_level)\n     {\n       if (used)\ndiff --git gcc/cp/parser.c gcc/cp/parser.c\nindex 47d91bfa9a7..0e3d00dbc47 100644\n--- gcc/cp/parser.c\n+++ gcc/cp/parser.c\n@@ -973,9 +973,10 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)\n     case RID_FLOAT:\n     case RID_DOUBLE:\n     case RID_VOID:\n-      /* GNU extensions.  */ \n+      /* GNU extensions.  */\n     case RID_ATTRIBUTE:\n     case RID_TYPEOF:\n+    case RID_REMOVE_QUALS:\n       /* C++0x extensions.  */\n     case RID_DECLTYPE:\n     case RID_UNDERLYING_TYPE:\n@@ -16960,6 +16961,24 @@ cp_parser_simple_type_specifier (cp_parser* parser,\n \n       return type;\n \n+    case RID_REMOVE_QUALS:\n+      /* Consume the `__remove_qualifiers' token.  */\n+      cp_lexer_consume_token (parser->lexer);\n+      /* Parse the operand to __remove_qualifiers`'.  */\n+      type = cp_parser_sizeof_operand (parser, RID_REMOVE_QUALS);\n+      if (!TYPE_P (type))\n+\t{\n+\t  error_at (token->location,\n+\t\t    \"%<__remove_qualifiers%> can only be applied to a type\");\n+\t  type = error_mark_node;\n+\t}\n+      if (decl_specs)\n+\tcp_parser_set_decl_spec_type (decl_specs, type,\n+\t\t\t\t      token,\n+\t\t\t\t      /*type_definition_p=*/false);\n+\n+      return type;\n+\n     case RID_UNDERLYING_TYPE:\n       type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);\n       if (decl_specs)\n@@ -27696,6 +27715,9 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)\n \t\t\t\t TYPENAME,\n \t\t\t\t /*initialized=*/0,\n \t\t\t\t /*attrlist=*/NULL);\n+\t  /* __remove_qualifiers removes all type qualifiers.  */\n+\t  if (keyword == RID_REMOVE_QUALS)\n+\t    expr = cp_build_qualified_type (expr, TYPE_UNQUALIFIED);\n \t}\n     }\n \ndiff --git gcc/doc/extend.texi gcc/doc/extend.texi\nindex 649be015dbb..749a9735f3b 100644\n--- gcc/doc/extend.texi\n+++ gcc/doc/extend.texi\n@@ -29,6 +29,7 @@ extensions, accepted by GCC in C90 mode and in C++.\n * Nested Functions::    As in Algol and Pascal, lexical scoping of functions.\n * Constructing Calls::  Dispatching a call to another function.\n * Typeof::              @code{typeof}: referring to the type of an expression.\n+* __remove_qualifiers::\tRemoving type qualifiers using @code{__remove_qualifiers}.\n * Conditionals::        Omitting the middle operand of a @samp{?:} expression.\n * __int128::\t\t128-bit integers---@code{__int128}.\n * Long Long::           Double-word integers---@code{long long int}.\n@@ -788,6 +789,37 @@ evaluated only once when using @code{__auto_type}, but twice if\n @code{typeof} is used.\n @end itemize\n \n+@node __remove_qualifiers\n+@section Removing type qualifiers using @code{__remove_qualifiers}\n+@findex __remove_qualifiers\n+\n+@code{__remove_qualifiers} takes a typename as an argument:\n+\n+@smallexample\n+__remove_qualifiers (const int)\n+@end smallexample\n+\n+and produces the same type with all type qualifiers such as @code{const} and\n+@code{volatile} removed.  This is useful in combination with @code{typeof},\n+e.g. for certain macros when passed const arguments:\n+\n+@smallexample\n+#define MAX(x, y)                                \\\n+  (@{                                             \\\n+  __remove_qualifiers (__typeof (x)) ret = x;    \\\n+  if (y > ret) ret = y;                          \\\n+    ret;                                         \\\n+  @})\n+\n+const int ci = 5;\n+MAX (ci, 12);\n+@end smallexample\n+\n+In C++, it's possible to combine @code{__remove_qualifiers} with\n+@code{decltype} instead of @code{typeof}.\n+\n+It is an error to pass an expression as an argument.\n+\n @node Conditionals\n @section Conditionals with Omitted Operands\n @cindex conditional expressions, extensions\ndiff --git gcc/testsuite/c-c++-common/remove-quals-1.c gcc/testsuite/c-c++-common/remove-quals-1.c\nindex e69de29bb2d..28464eb6b87 100644\n--- gcc/testsuite/c-c++-common/remove-quals-1.c\n+++ gcc/testsuite/c-c++-common/remove-quals-1.c\n@@ -0,0 +1,42 @@\n+/* PR c/65455 */\n+/* { dg-do compile } */\n+/* { dg-options \"-pedantic-errors\" } */\n+\n+void\n+foo (void)\n+{\n+  int i = 0;\n+  const int ci = 0;\n+  volatile int vi = 0;\n+\n+  __typeof(i) *ip = 0;\n+  __typeof(ci) *cip = 0;\n+  __typeof(vi) *vip = 0;\n+\n+  __remove_qualifiers (__typeof (i)) *nip = 0;\n+  __remove_qualifiers (__typeof (ci)) *ncip = 0;\n+  __remove_qualifiers (__typeof (vi)) *nvip = 0;\n+\n+  __remove_qualifiers (__typeof (i)) *nip2 = 0;\n+  __remove_qualifiers (__typeof (ci)) *ncip2 = 0;\n+  __remove_qualifiers (__typeof (vi)) *nvip2 = 0;\n+\n+  ip = cip;            /* { dg-error \"assignment discards|invalid conversion\" } */\n+  ip = vip;            /* { dg-error \"assignment discards|invalid conversion\" } */\n+\n+  ip = nip;\n+  ip = ncip;\n+  ip = nvip;\n+\n+  ip = nip2;\n+  ip = ncip2;\n+  ip = nvip2;\n+\n+  ncip = cip;          /* { dg-error \"assignment discards|invalid conversion\" } */\n+  nvip = vip;          /* { dg-error \"assignment discards|invalid conversion\" } */\n+  ncip2 = cip;         /* { dg-error \"assignment discards|invalid conversion\" } */\n+  nvip2 = vip;         /* { dg-error \"assignment discards|invalid conversion\" } */\n+\n+  nip = ip;\n+  nip2 = ip;\n+}\ndiff --git gcc/testsuite/c-c++-common/remove-quals-2.c gcc/testsuite/c-c++-common/remove-quals-2.c\nindex e69de29bb2d..fac314d52d8 100644\n--- gcc/testsuite/c-c++-common/remove-quals-2.c\n+++ gcc/testsuite/c-c++-common/remove-quals-2.c\n@@ -0,0 +1,32 @@\n+/* PR c/65455 */\n+/* { dg-do compile } */\n+\n+const int g(void);\n+\n+#define MAX(__x, __y)\t\t\t\t\t\\\n+  ({\t\t\t\t\t\t\t\\\n+  __remove_qualifiers (__typeof (__x)) __ret = __x;\t\\\n+  if (__y > __ret) __ret = __y;\t\t\t\t\\\n+    __ret;\t\t\t\t\t\t\\\n+  })\n+\n+void\n+fn (void)\n+{\n+  const int ci = 5;\n+  __remove_qualifiers (__typeof (({ ci; }))) n1;\n+  __remove_qualifiers (__typeof (ci)) n2;\n+  __typeof (g ()) n4;\n+  __remove_qualifiers (__typeof (g ())) n3;\n+\n+  typedef __remove_qualifiers (__typeof (ci)) T;\n+  T n5;\n+\n+  n1 = 5;\n+  n2 = 5;\n+  n3 = 5;\n+  n4 = 5;\n+  n5 = 5;\n+\n+  MAX (ci, 12);\n+}\ndiff --git gcc/testsuite/c-c++-common/remove-quals-3.c gcc/testsuite/c-c++-common/remove-quals-3.c\nindex e69de29bb2d..c3ace534adf 100644\n--- gcc/testsuite/c-c++-common/remove-quals-3.c\n+++ gcc/testsuite/c-c++-common/remove-quals-3.c\n@@ -0,0 +1,17 @@\n+/* PR c/65455 */\n+/* { dg-do run } */\n+\n+int\n+main ()\n+{\n+  __remove_qualifiers (const int) h;\n+  h = 9;\n+\n+  int i = 1;\n+  __typeof (int [++i]) e;\n+  __remove_qualifiers (int [++i]) e2;\n+  __remove_qualifiers (__typeof (int [++i])) e3;\n+\n+  if (i != 4)\n+    __builtin_abort ();\n+}\ndiff --git gcc/testsuite/c-c++-common/remove-quals-4.c gcc/testsuite/c-c++-common/remove-quals-4.c\nindex e69de29bb2d..d140f553345 100644\n--- gcc/testsuite/c-c++-common/remove-quals-4.c\n+++ gcc/testsuite/c-c++-common/remove-quals-4.c\n@@ -0,0 +1,15 @@\n+/* PR c/65455 */\n+/* { dg-do compile } */\n+/* { dg-options \"-Wall -Wextra -Wpedantic -Wno-unused -Wno-vla\" } */\n+\n+void\n+fn (void)\n+{\n+  __typeof (int [1 / 0]) t1;\n+  __remove_qualifiers (int [1 / 0]) t2;\n+\n+  int i;\n+  __remove_qualifiers (i) t3; /* { dg-error \".__remove_qualifiers. can only be applied to a type|expected\" } */\n+  __remove_qualifiers (1) t4; /* { dg-error \".__remove_qualifiers. can only be applied to a type|expected\" } */\n+  __remove_qualifiers (int []) t5; /* { dg-error \"array size|storage size\" } */\n+}\ndiff --git gcc/testsuite/g++.dg/ext/remove-quals-1.C gcc/testsuite/g++.dg/ext/remove-quals-1.C\nindex e69de29bb2d..0d0e33538b2 100644\n--- gcc/testsuite/g++.dg/ext/remove-quals-1.C\n+++ gcc/testsuite/g++.dg/ext/remove-quals-1.C\n@@ -0,0 +1,12 @@\n+// PR c/65455\n+// { dg-do compile }\n+// { dg-options \"-pedantic-errors\" }\n+\n+void\n+fn (void)\n+{\n+  signed __remove_qualifiers (const int) s; /* { dg-error \"used invalidly\" } */\n+\n+  __typeof (struct S { int i; }) q; /* { dg-error \"types may not be defined in .typeof. expressions\" } */\n+  __remove_qualifiers (struct S2 { int i; }) q2; /* { dg-error \"types may not be defined in .__remove_qualifiers__. expressions\" } */\n+}\ndiff --git gcc/testsuite/g++.dg/ext/remove-quals-2.C gcc/testsuite/g++.dg/ext/remove-quals-2.C\nindex e69de29bb2d..10f7b5c5d7c 100644\n--- gcc/testsuite/g++.dg/ext/remove-quals-2.C\n+++ gcc/testsuite/g++.dg/ext/remove-quals-2.C\n@@ -0,0 +1,25 @@\n+// PR c/65455\n+// { dg-do compile { target c++11 } }\n+\n+template<typename T, typename U>\n+struct is_same\n+{\n+  static const bool value = false;\n+};\n+\n+template<typename T>\n+struct is_same<T, T>\n+{\n+  static const bool value = true;\n+};\n+\n+const int x = 1;\n+typedef __remove_qualifiers (decltype (x)) T;\n+T y = 1;\n+volatile int i;\n+static_assert(is_same<__remove_qualifiers (decltype (x)), int>::value,\n+\t      \"type should be int\");\n+static_assert(is_same<decltype (y), int>::value,\n+\t      \"type should be int\");\n+static_assert(is_same<__remove_qualifiers (decltype (i)), int>::value,\n+\t      \"type should be int\");\ndiff --git gcc/testsuite/gcc.dg/auto-type-3.c gcc/testsuite/gcc.dg/auto-type-3.c\nindex e69de29bb2d..79479c80084 100644\n--- gcc/testsuite/gcc.dg/auto-type-3.c\n+++ gcc/testsuite/gcc.dg/auto-type-3.c\n@@ -0,0 +1,25 @@\n+/* { dg-do compile } */\n+/* { dg-options \"\" } */\n+\n+struct S\n+{\n+  int k;\n+};\n+\n+void\n+foo (void)\n+{\n+  _Atomic register const int a = 3;\n+  const int b = 16;\n+  const struct S s;\n+  int *const c = 0;\n+\n+  __auto_type i = a;\n+  i++;\n+  __auto_type j = b;\n+  j++;\n+  __auto_type k = s.k;\n+  k++;\n+  __auto_type l = c;\n+  l++;\n+}\ndiff --git gcc/testsuite/gcc.dg/remove-quals-1.c gcc/testsuite/gcc.dg/remove-quals-1.c\nindex e69de29bb2d..aecc17c949b 100644\n--- gcc/testsuite/gcc.dg/remove-quals-1.c\n+++ gcc/testsuite/gcc.dg/remove-quals-1.c\n@@ -0,0 +1,23 @@\n+/* PR c/65455 */\n+/* { dg-do compile } */\n+/* { dg-options \"-Wrestrict\" } */\n+\n+int *restrict t;\n+\n+void\n+bar (__remove_qualifiers (__typeof (t)) p, __remove_qualifiers (__typeof (t)) q)\n+{\n+}\n+\n+void\n+baz (__typeof (t) p, __typeof (t) q)\n+{\n+}\n+\n+void\n+foo (void)\n+{\n+  int i = 42;\n+  bar (&i, &i);\n+  baz (&i, &i); /* { dg-warning \"passing argument 1 to restrict-qualified parameter aliases\" } */\n+}\ndiff --git gcc/testsuite/gcc.dg/remove-quals-2.c gcc/testsuite/gcc.dg/remove-quals-2.c\nindex e69de29bb2d..2d13bf2b34e 100644\n--- gcc/testsuite/gcc.dg/remove-quals-2.c\n+++ gcc/testsuite/gcc.dg/remove-quals-2.c\n@@ -0,0 +1,12 @@\n+/* PR c/65455 */\n+/* { dg-do compile } */\n+/* { dg-options \"-Wc++-compat\" } */\n+\n+void\n+fn (void)\n+{\n+  signed __remove_qualifiers (const int) s; /* { dg-error \"two or more data types in declaration specifiers\" } */\n+\n+  __typeof (struct S { int i; }) q; /* { dg-warning \"defining type in .typeof. expression is invalid\" } */\n+  __remove_qualifiers (struct S2 { int i; }) q2; /* { dg-warning \"defining type in .__remove_qualifiers. expression is invalid\" } */\n+}\n",
    "prefixes": []
}