Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/808283/?format=api
{ "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": [] }