From patchwork Mon Jun 26 15:09:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 780753 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wxCC92CFHz9s81 for ; Tue, 27 Jun 2017 01:09:39 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="C+568HoB"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=U8L5Np7jk5UtdSRWJ vvPkG0XNr1rxJLLmOp3cz1d10FSmH6Kj9//NCTJraMFfIOVd0S5PStaFjBqLjNAq bewadXXJMM8brpDASgivbB66IdiDOIzxz3V9QKZNG32NZi7pte+Jjz1nk4GMajKs lhcuZSmo8PHEt5hjGLIMvUCxyM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=default; bh=QJ0rzq7TsA6QKnpdovytI3C HxBs=; b=C+568HoBTimLqMjB9CfhFVfepJNgV1d+hTyV3rzVfc/0DoPgszM1WWM 9GF+EoxHGGtP95YZUsuPqyEVZsPQ2MeZ1sOYYJNKoCTO2WPH3/Masd2Ds7ncKEzU lr9q3jsRjADj7W73+cmBYGy/ed+Bf0fBxmtNpzTAGWR4enQHa58A= Received: (qmail 64891 invoked by alias); 26 Jun 2017 15:09:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 64726 invoked by uid 89); 26 Jun 2017 15:09:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=UD:k, sk X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 26 Jun 2017 15:09:23 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 490008B13F; Mon, 26 Jun 2017 15:09:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 490008B13F Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=polacek@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 490008B13F Received: from redhat.com (ovpn-204-53.brq.redhat.com [10.40.204.53]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B69B57B55B; Mon, 26 Jun 2017 15:09:20 +0000 (UTC) Date: Mon, 26 Jun 2017 17:09:18 +0200 From: Marek Polacek To: Joseph Myers Cc: GCC Patches , Jason Merrill Subject: Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985) Message-ID: <20170626150918.GG4341@redhat.com> References: <20170623144606.GB4341@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.8.0 (2017-02-23) On Fri, Jun 23, 2017 at 04:27:47PM +0000, Joseph Myers wrote: > On Fri, 23 Jun 2017, Marek Polacek wrote: > > > You'll also see that I dropped all qualifiers for __auto_type. But I actually > > couldn't trigger the > > init_type = c_build_qualified_type (init_type, TYPE_UNQUALIFIED); > > line in c_parser_declaration_or_fndef (even when running the whole testsuite) > > so I'm not convinced it makes any difference. > > It looks like it would only make a difference, in the present code, for > the case of an atomic register variable, or bit-field in an atomic > structure, as the initializer. Those are the cases where Ah, right. But since __auto_type doesn't work with bit-fields, I only tested the register variant. > convert_lvalue_to_rvalue would not return a non-atomic result, given an > atomic argument. With the proposed change, it should apply to any > qualified lvalue used as the initializer. Right. > > @@ -506,6 +508,7 @@ const struct c_common_resword c_common_reswords[] = > > { "typename", RID_TYPENAME, D_CXXONLY | D_CXXWARN }, > > { "typeid", RID_TYPEID, D_CXXONLY | D_CXXWARN }, > > { "typeof", RID_TYPEOF, D_ASM | D_EXT }, > > + { "typeof_noqual", RID_TYPEOF_NOQUAL, D_ASM | D_EXT }, > > { "union", RID_UNION, 0 }, > > { "unsigned", RID_UNSIGNED, 0 }, > > { "using", RID_USING, D_CXXONLY | D_CXXWARN }, > > I don't think we should have this keyword variant. Ok, dropped. > I think there should be tests of the change to __auto_type. I've added one. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2017-06-26 Marek Polacek Richard Henderson PR c/65455 PR c/39985 * c-common.c (c_common_reswords): Add __typeof_noqual and __typeof_noqual__. (keyword_begins_type_specifier): Handle RID_TYPEOF_NOQUAL. * c-common.h (enum rid): Add RID_TYPEOF_NOQUAL. * c-parser.c (c_keyword_starts_typename): Handle RID_TYPEOF_NOQUAL. (c_token_starts_declspecs): Likewise. (c_parser_declaration_or_fndef): Always strip all qualifiers for __auto_type. (c_parser_declspecs): Handle RID_TYPEOF_NOQUAL. (c_parser_typeof_specifier): Handle RID_TYPEOF_NOQUAL by dropping all the qualifiers. (c_parser_objc_selector): Handle RID_TYPEOF_NOQUAL. * parser.c (cp_keyword_starts_decl_specifier_p): Handle RID_TYPEOF_NOQUAL. (cp_parser_simple_type_specifier): Handle RID_TYPEOF_NOQUAL by dropping all the qualifiers. * doc/extend.texi: Document __typeof_noqual. * c-c++-common/typeof-noqual-1.c: New test. * c-c++-common/typeof-noqual-2.c: New test. * gcc.dg/typeof-noqual-1.c: New test. * gcc.dg/auto-type-3.c: New test. Marek diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c index f6a9d05..7993de2 100644 --- gcc/c-family/c-common.c +++ gcc/c-family/c-common.c @@ -433,6 +433,8 @@ const struct c_common_resword c_common_reswords[] = { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 }, { "__typeof", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 }, + { "__typeof_noqual", RID_TYPEOF_NOQUAL, 0 }, + { "__typeof_noqual__", RID_TYPEOF_NOQUAL, 0 }, { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, @@ -7511,6 +7513,7 @@ keyword_begins_type_specifier (enum rid keyword) case RID_SAT: case RID_COMPLEX: case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: case RID_STRUCT: case RID_CLASS: case RID_UNION: diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h index f3d051a..ad00ae8 100644 --- gcc/c-family/c-common.h +++ gcc/c-family/c-common.h @@ -100,8 +100,9 @@ enum rid /* C extensions */ RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, - RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, - RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, + RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, + RID_BUILTIN_SHUFFLE, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, + RID_TYPEOF_NOQUAL, /* TS 18661-3 keywords, in the same sequence as the TI_* values. */ RID_FLOAT16, diff --git gcc/c/c-parser.c gcc/c/c-parser.c index f8fbc92..eb6cfad 100644 --- gcc/c/c-parser.c +++ gcc/c/c-parser.c @@ -495,6 +495,7 @@ c_keyword_starts_typename (enum rid keyword) case RID_STRUCT: case RID_UNION: case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: case RID_CONST: case RID_ATOMIC: case RID_VOLATILE: @@ -671,6 +672,7 @@ c_token_starts_declspecs (c_token *token) case RID_STRUCT: case RID_UNION: case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: case RID_CONST: case RID_VOLATILE: case RID_RESTRICT: @@ -1875,8 +1877,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, " initializer"); init = convert_lvalue_to_rvalue (init_loc, init, true, true); tree init_type = TREE_TYPE (init.value); - /* As with typeof, remove all qualifiers from atomic types. */ - if (init_type != error_mark_node && TYPE_ATOMIC (init_type)) + /* As with __typeof_noqual, remove all qualifiers. */ + if (init_type != error_mark_node) init_type = c_build_qualified_type (init_type, TYPE_UNQUALIFIED); bool vm_type = variably_modified_type_p (init_type, @@ -2557,6 +2559,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, declspecs_add_type (loc, specs, t); break; case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: /* ??? The old parser rejected typeof after other type specifiers, but is a syntax error the best way of handling this? */ @@ -3220,7 +3223,10 @@ c_parser_typeof_specifier (c_parser *parser) ret.spec = error_mark_node; ret.expr = NULL_TREE; ret.expr_const_operands = true; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); + + enum rid keyword = c_parser_peek_token (parser)->keyword; + gcc_assert (keyword == RID_TYPEOF || keyword == RID_TYPEOF_NOQUAL); + c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; in_typeof++; @@ -3262,7 +3268,9 @@ c_parser_typeof_specifier (c_parser *parser) /* For use in macros such as those in , remove all qualifiers from atomic types. (const can be an issue for more macros using typeof than just the ones.) */ - if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec)) + if (ret.spec != error_mark_node + /* __typeof_noqual also drops the qualifiers. */ + && (TYPE_ATOMIC (ret.spec) || keyword == RID_TYPEOF_NOQUAL)) ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED); } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); @@ -9746,6 +9754,7 @@ c_parser_objc_selector (c_parser *parser) case RID_ASM: case RID_SIZEOF: case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: case RID_ALIGNOF: case RID_UNSIGNED: case RID_LONG: diff --git gcc/cp/parser.c gcc/cp/parser.c index c405fe5..79aae2a 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -976,6 +976,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) /* GNU extensions. */ case RID_ATTRIBUTE: case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: /* C++0x extensions. */ case RID_DECLTYPE: case RID_UNDERLYING_TYPE: @@ -16867,6 +16868,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, break; case RID_TYPEOF: + case RID_TYPEOF_NOQUAL: /* Consume the `typeof' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the operand to `typeof'. */ @@ -16874,6 +16876,9 @@ cp_parser_simple_type_specifier (cp_parser* parser, /* If it is not already a TYPE, take its type. */ if (!TYPE_P (type)) type = finish_typeof (type); + /* If requested, make the type unqualified. */ + if (token->keyword == RID_TYPEOF_NOQUAL && type != error_mark_node) + type = cp_build_qualified_type (type, TYPE_UNQUALIFIED); if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type, diff --git gcc/doc/extend.texi gcc/doc/extend.texi index 43f9ecf..acfd7e8 100644 --- gcc/doc/extend.texi +++ gcc/doc/extend.texi @@ -155,7 +155,8 @@ the value of an enumeration constant, the width of a bit-field, or the initial value of a static variable. If you don't know the type of the operand, you can still do this, but you -must use @code{typeof} or @code{__auto_type} (@pxref{Typeof}). +must use @code{typeof}, @code{__typeof_noqual}, or @code{__auto_type} +(@pxref{Typeof}). In G++, the result value of a statement expression undergoes array and function pointer decay, and is returned by value to the enclosing @@ -642,6 +643,7 @@ myopen (const char *path, int oflag, ...) @node Typeof @section Referring to a Type with @code{typeof} @findex typeof +@findex __typeof_noqual @findex sizeof @cindex macros, types of arguments @@ -694,6 +696,22 @@ arithmetic type and evaluates each of its arguments exactly once: _a > _b ? _a : _b; @}) @end smallexample +@code{__typeof_noqual} behaves the same except that it strips type qualifiers +such as @code{const} and @code{volatile}, if given an expression. This can +be useful for certain macros when passed const arguments: + +@smallexample +#define MAX(__x, __y) \ + (@{ \ + __typeof_noqual(__x) __ret = __x; \ + if (__y > __ret) __ret = __y; \ + __ret; \ + @}) + +const int ci = 5; +MAX (ci, 12); +@end smallexample + @cindex underscores in variables in macros @cindex @samp{_} in variables in macros @cindex local variables in macros diff --git gcc/testsuite/c-c++-common/typeof-noqual-1.c gcc/testsuite/c-c++-common/typeof-noqual-1.c index e69de29..455e51f 100644 --- gcc/testsuite/c-c++-common/typeof-noqual-1.c +++ gcc/testsuite/c-c++-common/typeof-noqual-1.c @@ -0,0 +1,42 @@ +/* PR c/65455 */ +/* { dg-do compile } */ +/* { dg-options "-pedantic-errors" } */ + +void +foo (void) +{ + int i = 0; + const int ci = 0; + volatile int vi = 0; + + __typeof(i) *ip = 0; + __typeof(ci) *cip = 0; + __typeof(vi) *vip = 0; + + __typeof_noqual(i) *nip = 0; + __typeof_noqual(ci) *ncip = 0; + __typeof_noqual(vi) *nvip = 0; + + __typeof_noqual__(i) *nip2 = 0; + __typeof_noqual__(ci) *ncip2 = 0; + __typeof_noqual__(vi) *nvip2 = 0; + + ip = cip; /* { dg-error "assignment discards|invalid conversion" } */ + ip = vip; /* { dg-error "assignment discards|invalid conversion" } */ + + ip = nip; + ip = ncip; + ip = nvip; + + ip = nip2; + ip = ncip2; + ip = nvip2; + + ncip = cip; /* { dg-error "assignment discards|invalid conversion" } */ + nvip = vip; /* { dg-error "assignment discards|invalid conversion" } */ + ncip2 = cip; /* { dg-error "assignment discards|invalid conversion" } */ + nvip2 = vip; /* { dg-error "assignment discards|invalid conversion" } */ + + nip = ip; + nip2 = ip; +} diff --git gcc/testsuite/c-c++-common/typeof-noqual-2.c gcc/testsuite/c-c++-common/typeof-noqual-2.c index e69de29..1a27e44 100644 --- gcc/testsuite/c-c++-common/typeof-noqual-2.c +++ gcc/testsuite/c-c++-common/typeof-noqual-2.c @@ -0,0 +1,32 @@ +/* PR c/65455 */ +/* { dg-do compile } */ + +const int g(void); + +#define MAX(__x, __y) \ + ({ \ + __typeof_noqual(__x) __ret = __x; \ + if (__y > __ret) __ret = __y; \ + __ret; \ + }) + +void +fn (void) +{ + const int ci = 5; + __typeof_noqual (({ ci; })) n1; + __typeof_noqual (ci) n2; + __typeof (g ()) n4; + __typeof_noqual (g ()) n3; + + typedef __typeof_noqual(ci) T; + T n5; + + n1 = 5; + n2 = 5; + n3 = 5; + n4 = 5; + n5 = 5; + + MAX (ci, 12); +} diff --git gcc/testsuite/gcc.dg/auto-type-3.c gcc/testsuite/gcc.dg/auto-type-3.c index e69de29..79479c8 100644 --- gcc/testsuite/gcc.dg/auto-type-3.c +++ gcc/testsuite/gcc.dg/auto-type-3.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct S +{ + int k; +}; + +void +foo (void) +{ + _Atomic register const int a = 3; + const int b = 16; + const struct S s; + int *const c = 0; + + __auto_type i = a; + i++; + __auto_type j = b; + j++; + __auto_type k = s.k; + k++; + __auto_type l = c; + l++; +} diff --git gcc/testsuite/gcc.dg/typeof-noqual-1.c gcc/testsuite/gcc.dg/typeof-noqual-1.c index e69de29..ec72506 100644 --- gcc/testsuite/gcc.dg/typeof-noqual-1.c +++ gcc/testsuite/gcc.dg/typeof-noqual-1.c @@ -0,0 +1,23 @@ +/* PR c/65455 */ +/* { dg-do compile } */ +/* { dg-options "-Wrestrict" } */ + +int *restrict t; + +void +bar (__typeof_noqual (t) p, __typeof_noqual (t) q) +{ +} + +void +baz (__typeof (t) p, __typeof (t) q) +{ +} + +void +foo (void) +{ + int i = 42; + bar (&i, &i); + baz (&i, &i); /* { dg-warning "passing argument 1 to restrict-qualified parameter aliases" } */ +}