From patchwork Thu May 10 17:53:44 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 158357 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]) by ozlabs.org (Postfix) with SMTP id 26893B6F9A for ; Fri, 11 May 2012 03:54:49 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1337277290; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Cc:Subject:References:Date:In-Reply-To: Message-ID:User-Agent:MIME-Version:Content-Type: Content-Transfer-Encoding:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=QMhk4UCEao+/8BysK/19bvXy6fM=; b=LEtqTE3QXZH6FOz 0DO13v+Rcfl7bRdpb241jwcQ53ppF93rZzQxYqCrkjnaapIy0QgXHtbtSvhkzz92 ZRV+BMqxGgtym7Yfw2EU3w1bxYyHGVU1RkOiXTtcjtti8uDcDHs6aUXdMRyWpjaS FtQ5k0b7euVwd3ykVzyU5668tTMA= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:From:To:Cc:Subject:References:X-URL:Date:In-Reply-To:Message-ID:User-Agent:MIME-Version:Content-Type:Content-Transfer-Encoding:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=OlSzhC+CXj3Te///3+tZv3y4rlSrTjp9C7pfjR8TBbIGTBSM5/rRIwwg2chQFc diOgoo72v+1209EZQ4bBDY9UWDNpjO0DIzjHlWOkldLjM8s9+fWaUfmeFMupOPeT kNRfeWEkekOJa8I3NiPSPDjQy9GqEy07dc2x8uCnqRV/I=; Received: (qmail 12775 invoked by alias); 10 May 2012 17:54:36 -0000 Received: (qmail 12737 invoked by uid 22791); 10 May 2012 17:54:17 -0000 X-SWARE-Spam-Status: No, hits=-5.6 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_BJ, TW_CD, TW_CX, TW_PD, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 10 May 2012 17:53:48 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q4AHrlBI017259 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 10 May 2012 13:53:47 -0400 Received: from localhost (ovpn-116-69.ams2.redhat.com [10.36.116.69]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q4AHrjvA008620 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 10 May 2012 13:53:46 -0400 Received: by localhost (Postfix, from userid 500) id 17B0229C04A; Thu, 10 May 2012 19:53:45 +0200 (CEST) From: Dodji Seketeli To: Jason Merrill Cc: Tom Tromey , Gabriel Dos Reis , GCC Patches Subject: Re: [PATCH] PR preprocessor/7263 - Avoid pedantic warnings on system headers macro tokens References: <4FA402A1.8050503@redhat.com> X-URL: http://www.redhat.com Date: Thu, 10 May 2012 19:53:44 +0200 In-Reply-To: <4FA402A1.8050503@redhat.com> (Jason Merrill's message of "Fri, 04 May 2012 12:24:01 -0400") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 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 Jason Merrill writes: > It seems like for most of the declspecs, having both the location and > a flag/count is unnecessary; instead of checking the flag, we can > check whether the location is set. That won't work for the "long long > long" check, but it should work for the others. You'll need to change > _check_decl_spec to take the new declspec and location rather than > have it iterate every time, but that seems worth doing anyway. > > So I don't think we need both cp_decl_spec and cp_decl_spec_word. OK. I have done this. I have removed cp_parser_check_decl_spec completely, and instead, introduced a new function set_and_check_decl_spec_loc that sets the location for a given decl spec, and does the check there. I hope this does what you had in mind. > >> error_at (location, "%<__thread%> before %qD", ridpointers[keyword]); >> decl_specs->specs[(int) ds_thread] = 0; >> + decl_specs->locations[cpdw_thread] = location; > > This error should use the stored __thread location, and then set it to > 0 rather than the location argument. Oops, right. Fixed. > >> + decl_specs->locations[cpdw_builtin_type_spec] = location; >> if (!decl_specs->type) >> { >> decl_specs->type = type_spec; >> decl_specs->type_definition_p = false; >> - decl_specs->type_location = location; >> + decl_specs->locations[cpdw_type_spec] = location; > > Why do we need cpdw_builtin_type_spec? [... ] > I agree that cpdw_type_spec makes sense. I just don't see why we need > the _builtin_ variant. Oops. My bad. I didn't finish what I wanted to do. I wanted to be able to use the precise location of the redefined type when we permerror about that redefinition, in check_tag_decl. Finished in the patch below. Is it a bit better? Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk. Thanks. libcpp/ PR preprocessor/7263 * include/cpplib.h (cpp_classify_number): Take a location parameter. * expr.c (SYNTAX_ERROR_AT, SYNTAX_ERROR2_AT): New diagnostic macros that take a location parameter. (cpp_classify_number): Take a (virtual) location parameter. Use it for diagnostics. Adjust comments. (eval_token): Take a location parameter. Pass it to cpp_classify_number and to diagnostic routines. (_cpp_parse_expr): Use virtual locations of tokens when parsing expressions. Pass a virtual location to eval_token and to diagnostic routines. gcc/c-family/ PR preprocessor/7263 * c-lex.c (c_lex_with_flags): Pass a virtual location to the call to cpp_classify_number. For diagnostics, use the precise location instead of the global input_location. gcc/ PR preprocessor/7263 * c-tree.h (enum c_declspec_word): Declare new enum. (struct c_declspecs::locations): New member. (declspecs_add_qual, declspecs_add_scspec) (declspecs_add_addrspace, declspecs_add_alignas): Take a new location parameter. * c-decl.c (build_null_declspecs): Initialize the new struct c_declspecs::locations member. (declspecs_add_addrspace): Take a location parameter for the address space. Store it onto declaration specifiers. (declspecs_add_qual): Likewise, take a location parameter for the qualifier. (declspecs_add_type): Likewise, take a location parameter for the type specifier. (declspecs_add_scspec): Likewise, take a location parameter for the storage class specifier. (declspecs_add_attrs): Likewise, take a location parameter for the first attribute. (declspecs_add_alignas): Likewise, take a location parameter for the alignas token. (finish_declspecs): For diagnostics, use the location of the relevant declspec, instead of the global input_location. * c-parser.c (c_parser_parameter_declaration): Pass the precise virtual location of the declspec to the declspecs-setters. (c_parser_declspecs): Likewise. Avoid calling c_parser_peek_token repeatedly. gcc/cp/ PR preprocessor/7263 * cp-tree.h (enum cp_decl_spec): Add new enumerators to cover all the possible declarator specifiers so far. (struct cp_decl_specifier_seq::locations): Declare new member. (cp_decl_specifier_seq::{specs, type_location}): Remove. (decl_spec_seq_has_spec_p): Declare new function. * parser.c (cp_parser_check_decl_spec): Remove. (set_and_check_decl_spec_loc): Define new static function. (decl_spec_seq_has_spec_p): Define new public function. (cp_parser_decl_specifier_seq, cp_parser_function_specifier_opt) (cp_parser_type_specifier, cp_parser_simple_type_specifier) (cp_parser_set_storage_class, cp_parser_set_decl_spec_type) (cp_parser_alias_declaration): Set the locations for each declspec, using set_and_check_decl_spec_loc. (cp_parser_explicit_instantiation, cp_parser_init_declarator) (cp_parser_member_declaration, cp_parser_init_declarator): Use the new declspec location for specifiers. Use the new decl_spec_seq_has_spec_p. (cp_parser_type_specifier_seq): Use the new set_and_check_decl_spec_loc. Stop using cp_parser_check_decl_spec. Use the new decl_spec_seq_has_spec_p. (, cp_parser_init_declarator): Use the new set_and_check_decl_spec_loc. (cp_parser_single_declaration, cp_parser_friend_p) (cp_parser_objc_class_ivars, cp_parser_objc_struct_declaration): Use the new decl_spec_seq_has_spec_p. * decl.c (check_tag_decl): Use new decl_spec_seq_has_spec_p. Use the more precise ds_redefined_builtin_type_spec location for diagnostics about re-declaring C++ built-in types. (start_decl, grokvardecl, grokdeclarator): Use the new decl_spec_seq_has_spec_p. gcc/testsuite/ PR preprocessor/7263 * gcc.dg/binary-constants-2.c: Run without tracking locations accross macro expansion. * gcc.dg/binary-constants-3.c: Likewise. * gcc.dg/cpp/sysmac2.c: Likewise. * testsuite/gcc.dg/nofixed-point-2.c: Adjust for more precise location. * gcc.dg/cpp/syshdr3.c: New test. * gcc.dg/cpp/syshdr3.h: New header for the new test above. * gcc.dg/system-binary-constants-1.c: New test. * gcc.dg/system-binary-constants-1.h: New header for the new test above. * g++.dg/cpp/syshdr3.C: New test. * g++.dg/cpp/syshdr3.h: New header the new test above. * g++.dg/system-binary-constants-1.C: New test. * g++.dg/system-binary-constants-1.h: New header the new test above. --- gcc/c-decl.c | 127 +++++++++--- gcc/c-family/c-lex.c | 4 +- gcc/c-parser.c | 22 +- gcc/c-tree.h | 54 ++++- gcc/cp/cp-tree.h | 21 ++- gcc/cp/decl.c | 80 ++++---- gcc/cp/decl2.c | 2 +- gcc/cp/parser.c | 255 +++++++++++++--------- gcc/testsuite/g++.dg/cpp/syshdr3.C | 16 ++ gcc/testsuite/g++.dg/cpp/syshdr3.h | 7 + gcc/testsuite/g++.dg/system-binary-constants-1.C | 18 ++ gcc/testsuite/g++.dg/system-binary-constants-1.h | 3 + gcc/testsuite/gcc.dg/binary-constants-2.c | 2 +- gcc/testsuite/gcc.dg/binary-constants-3.c | 2 +- gcc/testsuite/gcc.dg/cpp/pr7263-3.c | 2 +- gcc/testsuite/gcc.dg/cpp/syshdr3.c | 16 ++ gcc/testsuite/gcc.dg/cpp/syshdr3.h | 7 + gcc/testsuite/gcc.dg/cpp/sysmac1.c | 2 +- gcc/testsuite/gcc.dg/cpp/sysmac2.c | 2 +- gcc/testsuite/gcc.dg/nofixed-point-2.c | 6 +- gcc/testsuite/gcc.dg/system-binary-constants-1.c | 18 ++ gcc/testsuite/gcc.dg/system-binary-constants-1.h | 3 + libcpp/expr.c | 182 +++++++++------- libcpp/include/cpplib.h | 2 +- 24 files changed, 573 insertions(+), 280 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp/syshdr3.C create mode 100644 gcc/testsuite/g++.dg/cpp/syshdr3.h create mode 100644 gcc/testsuite/g++.dg/system-binary-constants-1.C create mode 100644 gcc/testsuite/g++.dg/system-binary-constants-1.h create mode 100644 gcc/testsuite/gcc.dg/cpp/syshdr3.c create mode 100644 gcc/testsuite/gcc.dg/cpp/syshdr3.h create mode 100644 gcc/testsuite/gcc.dg/system-binary-constants-1.c create mode 100644 gcc/testsuite/gcc.dg/system-binary-constants-1.h diff --git a/gcc/c-decl.c b/gcc/c-decl.c index e34c843..605f0b4 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -8785,6 +8785,7 @@ struct c_declspecs * build_null_declspecs (void) { struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs); + memset (&ret->locations, 0, cdw_number_of_elements); ret->type = 0; ret->expr = 0; ret->decl_attr = 0; @@ -8822,7 +8823,8 @@ build_null_declspecs (void) SPECS, returning SPECS. */ struct c_declspecs * -declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) +declspecs_add_addrspace (source_location location, + struct c_declspecs *specs, addr_space_t as) { specs->non_sc_seen_p = true; specs->declspecs_seen_p = true; @@ -8833,7 +8835,10 @@ declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) c_addr_space_name (as), c_addr_space_name (specs->address_space)); else - specs->address_space = as; + { + specs->address_space = as; + specs->locations[cdw_address_space] = location; + } return specs; } @@ -8841,7 +8846,8 @@ declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) returning SPECS. */ struct c_declspecs * -declspecs_add_qual (struct c_declspecs *specs, tree qual) +declspecs_add_qual (source_location loc, + struct c_declspecs *specs, tree qual) { enum rid i; bool dupe = false; @@ -8855,20 +8861,23 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual) case RID_CONST: dupe = specs->const_p; specs->const_p = true; + specs->locations[cdw_const] = loc; break; case RID_VOLATILE: dupe = specs->volatile_p; specs->volatile_p = true; + specs->locations[cdw_volatile] = loc; break; case RID_RESTRICT: dupe = specs->restrict_p; specs->restrict_p = true; + specs->locations[cdw_restrict] = loc; break; default: gcc_unreachable (); } if (dupe && !flag_isoc99) - pedwarn (input_location, OPT_Wpedantic, "duplicate %qE", qual); + pedwarn (loc, OPT_Wpedantic, "duplicate %qE", qual); return specs; } @@ -8921,6 +8930,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, pedwarn_c90 (loc, OPT_Wlong_long, "ISO C90 does not support %"); specs->long_long_p = 1; + specs->locations[cdw_long_long] = loc; break; } if (specs->short_p) @@ -8960,7 +8970,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both % and %<_Decimal128%> in " "declaration specifiers")); else - specs->long_p = true; + { + specs->long_p = true; + specs->locations[cdw_long] = loc; + } break; case RID_SHORT: dupe = specs->short_p; @@ -9005,7 +9018,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both % and %<_Decimal128%> in " "declaration specifiers")); else - specs->short_p = true; + { + specs->short_p = true; + specs->locations[cdw_short] = loc; + } break; case RID_SIGNED: dupe = specs->signed_p; @@ -9042,7 +9058,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both % and %<_Decimal128%> in " "declaration specifiers")); else - specs->signed_p = true; + { + specs->signed_p = true; + specs->locations[cdw_signed] = loc; + } break; case RID_UNSIGNED: dupe = specs->unsigned_p; @@ -9079,11 +9098,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both % and %<_Decimal128%> in " "declaration specifiers")); else - specs->unsigned_p = true; + { + specs->unsigned_p = true; + specs->locations[cdw_unsigned] = loc; + } break; case RID_COMPLEX: dupe = specs->complex_p; - if (!flag_isoc99 && !in_system_header) + if (!flag_isoc99 && !in_system_header_at (loc)) pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support complex types"); if (specs->typespec_word == cts_void) @@ -9119,7 +9141,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both % and %<_Sat%> in " "declaration specifiers")); else - specs->complex_p = true; + { + specs->complex_p = true; + specs->locations[cdw_complex] = loc; + } break; case RID_SAT: dupe = specs->saturating_p; @@ -9172,7 +9197,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and % in " "declaration specifiers")); else - specs->saturating_p = true; + { + specs->saturating_p = true; + specs->locations[cdw_saturating] = loc; + } break; default: gcc_unreachable (); @@ -9218,7 +9246,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<__int128%> and % in " "declaration specifiers")); else - specs->typespec_word = cts_int128; + { + specs->typespec_word = cts_int128; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_VOID: if (specs->long_p) @@ -9246,7 +9277,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and % in " "declaration specifiers")); else - specs->typespec_word = cts_void; + { + specs->typespec_word = cts_void; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_BOOL: if (specs->long_p) @@ -9274,7 +9308,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and %<_Bool%> in " "declaration specifiers")); else - specs->typespec_word = cts_bool; + { + specs->typespec_word = cts_bool; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_CHAR: if (specs->long_p) @@ -9290,7 +9327,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and % in " "declaration specifiers")); else - specs->typespec_word = cts_char; + { + specs->typespec_word = cts_char; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_INT: if (specs->saturating_p) @@ -9298,7 +9338,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and % in " "declaration specifiers")); else - specs->typespec_word = cts_int; + { + specs->typespec_word = cts_int; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_FLOAT: if (specs->long_p) @@ -9322,7 +9365,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and % in " "declaration specifiers")); else - specs->typespec_word = cts_float; + { + specs->typespec_word = cts_float; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_DOUBLE: if (specs->long_long_p) @@ -9346,7 +9392,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, ("both %<_Sat%> and % in " "declaration specifiers")); else - specs->typespec_word = cts_double; + { + specs->typespec_word = cts_double; + specs->locations[cdw_typespec] = loc; + } return specs; case RID_DFLOAT32: case RID_DFLOAT64: @@ -9400,6 +9449,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->typespec_word = cts_dfloat64; else specs->typespec_word = cts_dfloat128; + specs->locations[cdw_typespec] = loc; } if (!targetm.decimal_float_supported_p ()) error_at (loc, @@ -9425,6 +9475,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->typespec_word = cts_fract; else specs->typespec_word = cts_accum; + specs->locations[cdw_typespec] = loc; } if (!targetm.fixed_point_supported_p ()) error_at (loc, @@ -9458,6 +9509,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->decl_attr = DECL_ATTRIBUTES (type); specs->typedef_p = true; specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type); + specs->locations[cdw_typedef] = loc; /* If this typedef name is defined in a struct, then a C++ lookup would return a different value. */ @@ -9481,13 +9533,17 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, else if (TREE_TYPE (t) == error_mark_node) ; else - specs->type = TREE_TYPE (t); + { + specs->type = TREE_TYPE (t); + specs->locations[cdw_typespec] = loc; + } } else { if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof) { specs->typedef_p = true; + specs->locations[cdw_typedef] = loc; if (spec.expr) { if (specs->expr) @@ -9508,7 +9564,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, declaration specifiers SPECS, returning SPECS. */ struct c_declspecs * -declspecs_add_scspec (struct c_declspecs *specs, tree scspec) +declspecs_add_scspec (source_location loc, + struct c_declspecs *specs, + tree scspec) { enum rid i; enum c_storage_class n = csc_none; @@ -9529,11 +9587,13 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec) difference between gnu89 and C99 inline. */ dupe = false; specs->inline_p = true; + specs->locations[cdw_inline] = loc; break; case RID_NORETURN: /* Duplicate _Noreturn is permitted. */ dupe = false; specs->noreturn_p = true; + specs->locations[cdw_noreturn] = loc; break; case RID_THREAD: dupe = specs->thread_p; @@ -9544,7 +9604,10 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec) else if (specs->storage_class == csc_typedef) error ("%<__thread%> used with %"); else - specs->thread_p = true; + { + specs->thread_p = true; + specs->locations[cdw_thread] = loc; + } break; case RID_AUTO: n = csc_auto; @@ -9583,6 +9646,7 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec) else { specs->storage_class = n; + specs->locations[cdw_storage_class] = loc; if (n != csc_extern && n != csc_static && specs->thread_p) { error ("%<__thread%> used with %qE", scspec); @@ -9597,9 +9661,10 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec) returning SPECS. */ struct c_declspecs * -declspecs_add_attrs (struct c_declspecs *specs, tree attrs) +declspecs_add_attrs (source_location loc, struct c_declspecs *specs, tree attrs) { specs->attrs = chainon (attrs, specs->attrs); + specs->locations[cdw_attributes] = loc; specs->declspecs_seen_p = true; return specs; } @@ -9608,10 +9673,12 @@ declspecs_add_attrs (struct c_declspecs *specs, tree attrs) alignment is ALIGN) to the declaration specifiers SPECS, returning SPECS. */ struct c_declspecs * -declspecs_add_alignas (struct c_declspecs *specs, tree align) +declspecs_add_alignas (source_location loc, + struct c_declspecs *specs, tree align) { int align_log; specs->alignas_p = true; + specs->locations[cdw_alignas] = loc; if (align == error_mark_node) return specs; align_log = check_user_alignment (align, true); @@ -9652,9 +9719,11 @@ finish_declspecs (struct c_declspecs *specs) { if (specs->saturating_p) { - error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>"); + error_at (specs->locations[cdw_saturating], + "%<_Sat%> is used without %<_Fract%> or %<_Accum%>"); if (!targetm.fixed_point_supported_p ()) - error ("fixed-point types not supported for this target"); + error_at (specs->locations[cdw_saturating], + "fixed-point types not supported for this target"); specs->typespec_word = cts_fract; } else if (specs->long_p || specs->short_p @@ -9665,7 +9734,7 @@ finish_declspecs (struct c_declspecs *specs) else if (specs->complex_p) { specs->typespec_word = cts_double; - pedwarn (input_location, OPT_Wpedantic, + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, "ISO C does not support plain % meaning " "%"); } @@ -9710,7 +9779,7 @@ finish_declspecs (struct c_declspecs *specs) specs->type = char_type_node; if (specs->complex_p) { - pedwarn (input_location, OPT_Wpedantic, + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, "ISO C does not support complex integer types"); specs->type = build_complex_type (specs->type); } @@ -9723,7 +9792,7 @@ finish_declspecs (struct c_declspecs *specs) : int128_integer_type_node); if (specs->complex_p) { - pedwarn (input_location, OPT_Wpedantic, + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, "ISO C does not support complex integer types"); specs->type = build_complex_type (specs->type); } @@ -9749,7 +9818,7 @@ finish_declspecs (struct c_declspecs *specs) : integer_type_node); if (specs->complex_p) { - pedwarn (input_location, OPT_Wpedantic, + pedwarn (specs->locations[cdw_complex], OPT_Wpedantic, "ISO C does not support complex integer types"); specs->type = build_complex_type (specs->type); } diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index 2a605f6..b122dab 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -315,7 +315,7 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, case CPP_NUMBER: { const char *suffix = NULL; - unsigned int flags = cpp_classify_number (parse_in, tok, &suffix); + unsigned int flags = cpp_classify_number (parse_in, tok, &suffix, *loc); switch (flags & CPP_N_CATEGORY) { @@ -417,7 +417,7 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, *cpp_spell_token (parse_in, tok, name, true) = 0; - error ("stray %qs in program", name); + error_at (*loc, "stray %qs in program", name); } goto retry; diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 87e43dc..85e12eb 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -2015,14 +2015,15 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, if (c_parser_next_token_is (parser, CPP_NAME)) { - tree value = c_parser_peek_token (parser)->value; - c_id_kind kind = c_parser_peek_token (parser)->id_kind; + c_token *name_token = c_parser_peek_token (parser); + tree value = name_token->value; + c_id_kind kind = name_token->id_kind; if (kind == C_ID_ADDRSPACE) { addr_space_t as - = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE; - declspecs_add_addrspace (specs, as); + = name_token->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (name_token->location, specs, as); c_parser_consume_token (parser); attrs_ok = true; continue; @@ -2068,7 +2069,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, } t.expr = NULL_TREE; t.expr_const_operands = true; - declspecs_add_type (loc, specs, t); + declspecs_add_type (name_token->location, specs, t); continue; } if (c_parser_next_token_is (parser, CPP_LESS)) @@ -2104,7 +2105,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, /* TODO: Distinguish between function specifiers (inline, noreturn) and storage class specifiers, either here or in declspecs_add_scspec. */ - declspecs_add_scspec (specs, c_parser_peek_token (parser)->value); + declspecs_add_scspec (loc, specs, + c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; case RID_UNSIGNED: @@ -2171,18 +2173,18 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, case RID_VOLATILE: case RID_RESTRICT: attrs_ok = true; - declspecs_add_qual (specs, c_parser_peek_token (parser)->value); + declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; case RID_ATTRIBUTE: if (!attrs_ok) goto out; attrs = c_parser_attributes (parser); - declspecs_add_attrs (specs, attrs); + declspecs_add_attrs (loc, specs, attrs); break; case RID_ALIGNAS: align = c_parser_alignas_specifier (parser); - declspecs_add_alignas (specs, align); + declspecs_add_alignas (loc, specs, align); break; default: goto out; @@ -3332,7 +3334,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) specs = build_null_declspecs (); if (attrs) { - declspecs_add_attrs (specs, attrs); + declspecs_add_attrs (input_location, specs, attrs); attrs = NULL_TREE; } c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl); diff --git a/gcc/c-tree.h b/gcc/c-tree.h index db60935..151e533 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -222,8 +222,45 @@ enum c_typespec_keyword { cts_accum }; -/* A sequence of declaration specifiers in C. */ +/* This enum lists all the possible declarator specifiers, storage + class or attribute that a user can write. There is at least one + enumerator per possible declarator specifier in the struct + c_declspecs below. + + It is used to index the array of declspec locations in struct + c_declspecs. */ +enum c_declspec_word { + cdw_typespec /* A catch-all for a typespec. */, + cdw_storage_class /* A catch-all for a storage class */, + cdw_attributes, + cdw_typedef, + cdw_explicit_signed, + cdw_deprecated, + cdw_default_int, + cdw_long, + cdw_long_long, + cdw_short, + cdw_signed, + cdw_unsigned, + cdw_complex, + cdw_inline, + cdw_noreturn, + cdw_thread, + cdw_const, + cdw_volatile, + cdw_restrict, + cdw_saturating, + cdw_alignas, + cdw_address_space, + cdw_number_of_elements /* This one must always be the last + enumerator. */ +}; + +/* A sequence of declaration specifiers in C. When a new declaration + specifier is added, please update the enum c_declspec_word above + accordingly. */ struct c_declspecs { + source_location locations[cdw_number_of_elements]; /* The type specified, if a single type specifier such as a struct, union or enum specifier, typedef name or typeof specifies the whole type, or NULL_TREE if none or a keyword such as "void" or @@ -509,15 +546,20 @@ extern struct c_declarator *build_id_declarator (tree); extern struct c_declarator *make_pointer_declarator (struct c_declspecs *, struct c_declarator *); extern struct c_declspecs *build_null_declspecs (void); -extern struct c_declspecs *declspecs_add_qual (struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_qual (source_location, + struct c_declspecs *, tree); extern struct c_declspecs *declspecs_add_type (location_t, struct c_declspecs *, struct c_typespec); -extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree); -extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree); -extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *, +extern struct c_declspecs *declspecs_add_scspec (source_location, + struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_attrs (source_location, + struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_addrspace (source_location, + struct c_declspecs *, addr_space_t); -extern struct c_declspecs *declspecs_add_alignas (struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_alignas (source_location, + struct c_declspecs *, tree); extern struct c_declspecs *finish_declspecs (struct c_declspecs *); /* in c-objc-common.c */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 5a7ebae..b450e52 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4643,7 +4643,9 @@ typedef enum cp_storage_class { sc_mutable } cp_storage_class; -/* An individual decl-specifier. */ +/* An individual decl-specifier. This is used to index the array of + locations for the declspecs in struct cp_decl_specifier_seq + below. */ typedef enum cp_decl_spec { ds_first, @@ -4663,17 +4665,20 @@ typedef enum cp_decl_spec { ds_constexpr, ds_complex, ds_thread, - ds_last + ds_type_spec, + ds_redefined_builtin_type_spec, + ds_attribute, + ds_storage_class, + ds_long_long, + ds_last /* This enumerator must always be the last one. */ } cp_decl_spec; /* A decl-specifier-seq. */ typedef struct cp_decl_specifier_seq { - /* The number of times each of the keywords has been seen. */ - unsigned specs[(int) ds_last]; - /* The location of the primary type. Mainly used for error - reporting. */ - location_t type_location; + /* An array of locations for the declaration sepecifiers, indexed by + enum cp_decl_spec_word. */ + source_location locations[ds_last]; /* The primary type, if any, given by the decl-specifier-seq. Modifiers, like "short", "const", and "unsigned" are not reflected here. This field will be a TYPE, unless a typedef-name @@ -4823,6 +4828,8 @@ struct GTY((chain_next ("%h.next"))) tinst_level { bool in_system_header_p; }; +bool decl_spec_seq_has_spec_p (const cp_decl_specifier_seq *, cp_decl_spec); + /* Return the type of the `this' parameter of FNTYPE. */ static inline tree diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 40818a3..de89ae3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4129,8 +4129,8 @@ fixup_anonymous_aggr (tree t) tree check_tag_decl (cp_decl_specifier_seq *declspecs) { - int saw_friend = declspecs->specs[(int)ds_friend] != 0; - int saw_typedef = declspecs->specs[(int)ds_typedef] != 0; + int saw_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend); + int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef); /* If a class, struct, or enum type is declared by the DECLSPECS (i.e, if a class-specifier, enum-specifier, or non-typename elaborated-type-specifier appears in the DECLSPECS), @@ -4143,7 +4143,8 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) else if (declspecs->redefined_builtin_type) { if (!in_system_header) - permerror (input_location, "redeclaration of C++ built-in type %qT", + permerror (declspecs->locations[ds_redefined_builtin_type_spec], + "redeclaration of C++ built-in type %qT", declspecs->redefined_builtin_type); return NULL_TREE; } @@ -4198,29 +4199,29 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) else { - if (declspecs->specs[(int)ds_inline] - || declspecs->specs[(int)ds_virtual]) + if (decl_spec_seq_has_spec_p (declspecs, ds_inline) + || decl_spec_seq_has_spec_p (declspecs, ds_virtual)) error ("%qs can only be specified for functions", - declspecs->specs[(int)ds_inline] + decl_spec_seq_has_spec_p (declspecs, ds_inline) ? "inline" : "virtual"); else if (saw_friend && (!current_class_type || current_scope () != current_class_type)) error ("% can only be specified inside a class"); - else if (declspecs->specs[(int)ds_explicit]) + else if (decl_spec_seq_has_spec_p (declspecs, ds_explicit)) error ("% can only be specified for constructors"); else if (declspecs->storage_class) error ("a storage class can only be specified for objects " "and functions"); - else if (declspecs->specs[(int)ds_const] - || declspecs->specs[(int)ds_volatile] - || declspecs->specs[(int)ds_restrict] - || declspecs->specs[(int)ds_thread]) + else if (decl_spec_seq_has_spec_p (declspecs, ds_const) + || decl_spec_seq_has_spec_p (declspecs, ds_volatile) + || decl_spec_seq_has_spec_p (declspecs, ds_restrict) + || decl_spec_seq_has_spec_p (declspecs, ds_thread)) error ("qualifiers can only be specified for objects " "and functions"); else if (saw_typedef) warning (0, "% was ignored in this declaration"); - else if (declspecs->specs[(int) ds_constexpr]) + else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr)) error ("% cannot be used for type declarations"); } @@ -4472,7 +4473,7 @@ start_decl (const cp_declarator *declarator, error ("duplicate initialization of %qD", decl); if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false)) decl = field; - if (declspecs->specs[(int) ds_constexpr] + if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr) && !DECL_DECLARED_CONSTEXPR_P (field)) error ("%qD declared % outside its class", field); } @@ -7682,7 +7683,7 @@ grokvardecl (tree type, TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); } - if (declspecs->specs[(int)ds_thread]) + if (decl_spec_seq_has_spec_p (declspecs, ds_thread)) DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); /* If the type of the decl has no linkage, make sure that we'll @@ -8436,16 +8437,16 @@ grokdeclarator (const cp_declarator *declarator, bool parameter_pack_p = declarator? declarator->parameter_pack_p : false; bool template_type_arg = false; bool template_parm_flag = false; - bool constexpr_p = declspecs->specs[(int) ds_constexpr]; + bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr); const char *errmsg; - signed_p = declspecs->specs[(int)ds_signed]; - unsigned_p = declspecs->specs[(int)ds_unsigned]; - short_p = declspecs->specs[(int)ds_short]; - long_p = declspecs->specs[(int)ds_long]; - longlong = declspecs->specs[(int)ds_long] >= 2; + signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed); + unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned); + short_p = decl_spec_seq_has_spec_p (declspecs, ds_short); + long_p = decl_spec_seq_has_spec_p (declspecs, ds_long); + longlong = decl_spec_seq_has_spec_p (declspecs, ds_long_long); explicit_int128 = declspecs->explicit_int128_p; - thread_p = declspecs->specs[(int)ds_thread]; + thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread); if (decl_context == FUNCDEF) funcdef_flag = true, decl_context = NORMAL; @@ -8646,7 +8647,7 @@ grokdeclarator (const cp_declarator *declarator, if (dname && IDENTIFIER_OPNAME_P (dname)) { - if (declspecs->specs[(int)ds_typedef]) + if (decl_spec_seq_has_spec_p (declspecs, ds_typedef)) { error ("declaration of %qD as %", dname); return error_mark_node; @@ -8684,7 +8685,7 @@ grokdeclarator (const cp_declarator *declarator, if (name == NULL) name = decl_context == PARM ? "parameter" : "type name"; - if (constexpr_p && declspecs->specs[(int)ds_typedef]) + if (constexpr_p && decl_spec_seq_has_spec_p (declspecs, ds_typedef)) { error ("% cannot appear in a typedef declaration"); return error_mark_node; @@ -8910,7 +8911,7 @@ grokdeclarator (const cp_declarator *declarator, else if (short_p) type = short_integer_type_node; - if (declspecs->specs[(int)ds_complex]) + if (decl_spec_seq_has_spec_p (declspecs, ds_complex)) { if (TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) error ("complex invalid for %qs", name); @@ -8934,11 +8935,11 @@ grokdeclarator (const cp_declarator *declarator, } type_quals = TYPE_UNQUALIFIED; - if (declspecs->specs[(int)ds_const]) + if (decl_spec_seq_has_spec_p (declspecs, ds_const)) type_quals |= TYPE_QUAL_CONST; - if (declspecs->specs[(int)ds_volatile]) + if (decl_spec_seq_has_spec_p (declspecs, ds_volatile)) type_quals |= TYPE_QUAL_VOLATILE; - if (declspecs->specs[(int)ds_restrict]) + if (decl_spec_seq_has_spec_p (declspecs, ds_restrict)) type_quals |= TYPE_QUAL_RESTRICT; if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED) error ("qualifiers are not allowed on declaration of %", @@ -8963,9 +8964,9 @@ grokdeclarator (const cp_declarator *declarator, type_quals = cp_type_quals (type); staticp = 0; - inlinep = !! declspecs->specs[(int)ds_inline]; - virtualp = !! declspecs->specs[(int)ds_virtual]; - explicitp = !! declspecs->specs[(int)ds_explicit]; + inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline); + virtualp = decl_spec_seq_has_spec_p (declspecs, ds_virtual); + explicitp = decl_spec_seq_has_spec_p (declspecs, ds_explicit); storage_class = declspecs->storage_class; if (storage_class == sc_static) @@ -8977,7 +8978,7 @@ grokdeclarator (const cp_declarator *declarator, storage_class = sc_none; staticp = 0; } - friendp = !! declspecs->specs[(int)ds_friend]; + friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend); if (dependent_name && !friendp) { @@ -8988,7 +8989,7 @@ grokdeclarator (const cp_declarator *declarator, /* Issue errors about use of storage classes for parameters. */ if (decl_context == PARM) { - if (declspecs->specs[(int)ds_typedef]) + if (decl_spec_seq_has_spec_p (declspecs, ds_typedef)) { error ("typedef declaration invalid in parameter declaration"); return error_mark_node; @@ -9032,7 +9033,7 @@ grokdeclarator (const cp_declarator *declarator, && ((storage_class && storage_class != sc_extern && storage_class != sc_static) - || declspecs->specs[(int)ds_typedef])) + || decl_spec_seq_has_spec_p (declspecs, ds_typedef))) { error ("multiple storage classes in declaration of %qs", name); thread_p = false; @@ -9046,7 +9047,7 @@ grokdeclarator (const cp_declarator *declarator, && (storage_class == sc_register || storage_class == sc_auto)) ; - else if (declspecs->specs[(int)ds_typedef]) + else if (decl_spec_seq_has_spec_p (declspecs, ds_typedef)) ; else if (decl_context == FIELD /* C++ allows static class elements. */ @@ -9640,7 +9641,7 @@ grokdeclarator (const cp_declarator *declarator, return error_mark_node; } } - else if (declspecs->specs[(int)ds_typedef] + else if (decl_spec_seq_has_spec_p (declspecs, ds_typedef) && current_class_type) { error ("cannot declare member %<%T::%s%> within %qT", @@ -9711,7 +9712,8 @@ grokdeclarator (const cp_declarator *declarator, error ("non-member %qs cannot be declared %", name); storage_class = sc_none; } - else if (decl_context == TYPENAME || declspecs->specs[(int)ds_typedef]) + else if (decl_context == TYPENAME + || decl_spec_seq_has_spec_p (declspecs, ds_typedef)) { error ("non-object member %qs cannot be declared %", name); storage_class = sc_none; @@ -9741,7 +9743,7 @@ grokdeclarator (const cp_declarator *declarator, } /* If this is declaring a typedef name, return a TYPE_DECL. */ - if (declspecs->specs[(int)ds_typedef] && decl_context != TYPENAME) + if (decl_spec_seq_has_spec_p (declspecs, ds_typedef) && decl_context != TYPENAME) { tree decl; @@ -9853,7 +9855,7 @@ grokdeclarator (const cp_declarator *declarator, memfn_quals != TYPE_UNQUALIFIED, inlinep, friendp, raises != NULL_TREE); - if (declspecs->specs[(int)ds_alias]) + if (decl_spec_seq_has_spec_p (declspecs, ds_alias)) /* Acknowledge that this was written: `using analias = atype;'. */ TYPE_DECL_ALIAS_P (decl) = 1; @@ -10352,7 +10354,7 @@ grokdeclarator (const cp_declarator *declarator, and `extern' makes no difference. */ if (! toplevel_bindings_p () && (storage_class == sc_static - || declspecs->specs[(int)ds_inline]) + || decl_spec_seq_has_spec_p (declspecs, ds_inline)) && pedantic) { if (storage_class == sc_static) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 34c969c..4f7b996 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -864,7 +864,7 @@ grokfield (const cp_declarator *declarator, cplus_decl_attributes (&value, attrlist, attrflags); } - if (declspecs->specs[(int)ds_typedef] + if (decl_spec_seq_has_spec_p (declspecs, ds_typedef) && TREE_TYPE (value) != error_mark_node && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value) set_underlying_type (value); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f0f7e98..1bb47ee 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2221,6 +2221,9 @@ static void cp_parser_set_storage_class (cp_parser *, cp_decl_specifier_seq *, enum rid, location_t); static void cp_parser_set_decl_spec_type (cp_decl_specifier_seq *, tree, location_t, bool); +static void set_and_check_decl_spec_loc + (cp_decl_specifier_seq *decl_specs, + cp_decl_spec ds, source_location location); static bool cp_parser_friend_p (const cp_decl_specifier_seq *); static void cp_parser_required_error @@ -2492,53 +2495,6 @@ cp_parser_simulate_error (cp_parser* parser) return false; } -/* Check for repeated decl-specifiers. */ - -static void -cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs, - location_t location) -{ - int ds; - - for (ds = ds_first; ds != ds_last; ++ds) - { - unsigned count = decl_specs->specs[ds]; - if (count < 2) - continue; - /* The "long" specifier is a special case because of "long long". */ - if (ds == ds_long) - { - if (count > 2) - error_at (location, "% is too long for GCC"); - else - pedwarn_cxx98 (location, OPT_Wlong_long, - "ISO C++ 1998 does not support %"); - } - else if (count > 1) - { - static const char *const decl_spec_names[] = { - "signed", - "unsigned", - "short", - "long", - "const", - "volatile", - "restrict", - "inline", - "virtual", - "explicit", - "friend", - "typedef", - "using", - "constexpr", - "__complex", - "__thread" - }; - error_at (location, "duplicate %qs", decl_spec_names[ds]); - } - } -} - /* This function is called when a type is defined. If type definitions are forbidden at this point, an error message is issued. */ @@ -10544,6 +10500,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, { bool constructor_possible_p = !parser->in_declarator_p; cp_token *start_token = NULL; + cp_decl_spec ds; /* Clear DECL_SPECS. */ clear_decl_specs (decl_specs); @@ -10557,6 +10514,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, bool constructor_p; bool found_decl_spec; cp_token *token; + ds = ds_last; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -10572,6 +10530,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser, decl_specs->attributes = chainon (decl_specs->attributes, cp_parser_attributes_opt (parser)); + if (decl_specs->locations[ds_attribute] == 0) + decl_specs->locations[ds_attribute] = token->location; continue; } /* Assume we will find a decl-specifier keyword. */ @@ -10591,14 +10551,14 @@ cp_parser_decl_specifier_seq (cp_parser* parser, } else { - ++decl_specs->specs[(int) ds_friend]; + ds = ds_friend; /* Consume the token. */ cp_lexer_consume_token (parser->lexer); } break; case RID_CONSTEXPR: - ++decl_specs->specs[(int) ds_constexpr]; + ds = ds_constexpr; cp_lexer_consume_token (parser->lexer); break; @@ -10615,7 +10575,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, /* decl-specifier: typedef */ case RID_TYPEDEF: - ++decl_specs->specs[(int) ds_typedef]; + ds = ds_typedef; /* Consume the token. */ cp_lexer_consume_token (parser->lexer); /* A constructor declarator cannot appear in a typedef. */ @@ -10668,8 +10628,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser, break; case RID_THREAD: /* Consume the token. */ + ds = ds_thread; cp_lexer_consume_token (parser->lexer); - ++decl_specs->specs[(int) ds_thread]; break; default: @@ -10683,13 +10643,16 @@ cp_parser_decl_specifier_seq (cp_parser* parser, && token->keyword != RID_CONSTEXPR) error ("decl-specifier invalid in condition"); + if (found_decl_spec && ds != ds_last) + set_and_check_decl_spec_loc (decl_specs, ds, token->location); + /* Constructors are a special case. The `S' in `S()' is not a decl-specifier; it is the beginning of the declarator. */ constructor_p = (!found_decl_spec && constructor_possible_p && (cp_parser_constructor_declarator_p - (parser, decl_specs->specs[(int) ds_friend] != 0))); + (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend)))); /* If we don't have a DECL_SPEC yet, then we must be looking at a type-specifier. */ @@ -10766,12 +10729,10 @@ cp_parser_decl_specifier_seq (cp_parser* parser, flags |= CP_PARSER_FLAGS_OPTIONAL; } - cp_parser_check_decl_spec (decl_specs, start_token->location); - /* Don't allow a friend specifier with a class definition. */ - if (decl_specs->specs[(int) ds_friend] != 0 + if (decl_spec_seq_has_spec_p (decl_specs, ds_friend) && (*declares_class_or_enum & 2)) - error_at (start_token->location, + error_at (decl_specs->locations[ds_friend], "class definition may not be declared a friend"); } @@ -10832,8 +10793,7 @@ cp_parser_function_specifier_opt (cp_parser* parser, switch (token->keyword) { case RID_INLINE: - if (decl_specs) - ++decl_specs->specs[(int) ds_inline]; + set_and_check_decl_spec_loc (decl_specs, ds_inline, token->location); break; case RID_VIRTUAL: @@ -10842,13 +10802,11 @@ cp_parser_function_specifier_opt (cp_parser* parser, A member function template shall not be virtual. */ if (PROCESSING_REAL_TEMPLATE_DECL_P ()) error_at (token->location, "templates may not be %"); - else if (decl_specs) - ++decl_specs->specs[(int) ds_virtual]; + set_and_check_decl_spec_loc (decl_specs, ds_virtual, token->location); break; case RID_EXPLICIT: - if (decl_specs) - ++decl_specs->specs[(int) ds_explicit]; + set_and_check_decl_spec_loc (decl_specs, ds_explicit, token->location); break; default: @@ -13155,13 +13113,13 @@ cp_parser_explicit_instantiation (cp_parser* parser) if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers.type, - decl_specifiers.type_location); + decl_specifiers.locations[ds_type_spec]); if (declarator != cp_error_declarator) { - if (decl_specifiers.specs[(int)ds_inline]) + if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_inline)) permerror (input_location, "explicit instantiation shall not use" " % specifier"); - if (decl_specifiers.specs[(int)ds_constexpr]) + if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_constexpr)) permerror (input_location, "explicit instantiation shall not use" " % specifier"); @@ -13384,7 +13342,7 @@ cp_parser_type_specifier (cp_parser* parser, type_spec = (cp_parser_elaborated_type_specifier (parser, - decl_specs && decl_specs->specs[(int) ds_friend], + decl_spec_seq_has_spec_p (decl_specs, ds_friend), is_declaration)); if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, @@ -13425,7 +13383,7 @@ cp_parser_type_specifier (cp_parser* parser, { if (decl_specs) { - ++decl_specs->specs[(int)ds]; + set_and_check_decl_spec_loc (decl_specs, ds, token->location); decl_specs->any_specifiers_p = true; } return cp_lexer_consume_token (parser->lexer)->u.value; @@ -13516,8 +13474,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, type = boolean_type_node; break; case RID_SHORT: - if (decl_specs) - ++decl_specs->specs[(int) ds_short]; + set_and_check_decl_spec_loc (decl_specs, ds_short, token->location); type = short_integer_type_node; break; case RID_INT: @@ -13534,17 +13491,15 @@ cp_parser_simple_type_specifier (cp_parser* parser, break; case RID_LONG: if (decl_specs) - ++decl_specs->specs[(int) ds_long]; + set_and_check_decl_spec_loc (decl_specs, ds_long, token->location); type = long_integer_type_node; break; case RID_SIGNED: - if (decl_specs) - ++decl_specs->specs[(int) ds_signed]; + set_and_check_decl_spec_loc (decl_specs, ds_signed, token->location); type = integer_type_node; break; case RID_UNSIGNED: - if (decl_specs) - ++decl_specs->specs[(int) ds_unsigned]; + set_and_check_decl_spec_loc (decl_specs, ds_unsigned, token->location); type = unsigned_type_node; break; case RID_FLOAT: @@ -15055,19 +15010,21 @@ static tree cp_parser_alias_declaration (cp_parser* parser) { tree id, type, decl, pushed_scope = NULL_TREE, attributes; - location_t id_location; + location_t id_location, using_location, attrs_location = 0; cp_declarator *declarator; cp_decl_specifier_seq decl_specs; bool member_p; const char *saved_message = NULL; /* Look for the `using' keyword. */ + using_location = cp_lexer_peek_token (parser->lexer)->location; cp_parser_require_keyword (parser, RID_USING, RT_USING); id_location = cp_lexer_peek_token (parser->lexer)->location; id = cp_parser_identifier (parser); if (id == error_mark_node) return error_mark_node; + attrs_location = cp_lexer_peek_token (parser->lexer)->location; attributes = cp_parser_attributes_opt (parser); if (attributes == error_mark_node) return error_mark_node; @@ -15116,9 +15073,19 @@ cp_parser_alias_declaration (cp_parser* parser) clear_decl_specs (&decl_specs); decl_specs.type = type; - decl_specs.attributes = attributes; - ++decl_specs.specs[(int) ds_typedef]; - ++decl_specs.specs[(int) ds_alias]; + if (attributes != NULL_TREE) + { + decl_specs.attributes = attributes; + set_and_check_decl_spec_loc (&decl_specs, + ds_attribute, + attrs_location); + } + set_and_check_decl_spec_loc (&decl_specs, + ds_typedef, + using_location); + set_and_check_decl_spec_loc (&decl_specs, + ds_alias, + using_location); declarator = make_id_declarator (NULL_TREE, id, sfk_none); declarator->id_loc = id_location; @@ -15500,7 +15467,7 @@ cp_parser_init_declarator (cp_parser* parser, if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers->type, - decl_specifiers->type_location); + decl_specifiers->locations[ds_type_spec]); /* Figure out what scope the entity declared by the DECLARATOR is located in. `grokdeclarator' sometimes changes the scope, so @@ -16921,8 +16888,6 @@ cp_parser_type_specifier_seq (cp_parser* parser, if (is_declaration && !is_cv_qualifier) flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES; } - - cp_parser_check_decl_spec (type_specifier_seq, start_token->location); } /* Parse a parameter-declaration-clause. @@ -19027,7 +18992,7 @@ cp_parser_member_declaration (cp_parser* parser) if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers.type, - decl_specifiers.type_location); + decl_specifiers.locations[ds_type_spec]); /* Look for an asm-specification. */ asm_specification = cp_parser_asm_specification_opt (parser); @@ -21286,7 +21251,7 @@ cp_parser_single_declaration (cp_parser* parser, *friend_p = cp_parser_friend_p (&decl_specifiers); /* There are no template typedefs. */ - if (decl_specifiers.specs[(int) ds_typedef]) + if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef)) { error_at (decl_spec_token_start->location, "template declaration of %"); @@ -22031,10 +21996,11 @@ cp_parser_set_storage_class (cp_parser *parser, } if ((keyword == RID_EXTERN || keyword == RID_STATIC) - && decl_specs->specs[(int) ds_thread]) + && decl_spec_seq_has_spec_p (decl_specs, ds_thread)) { - error_at (location, "%<__thread%> before %qD", ridpointers[keyword]); - decl_specs->specs[(int) ds_thread] = 0; + error_at (decl_specs->locations[ds_thread], + "%<__thread%> before %qD", ridpointers[keyword]); + decl_specs->locations[ds_thread] = 0; } switch (keyword) @@ -22058,12 +22024,13 @@ cp_parser_set_storage_class (cp_parser *parser, gcc_unreachable (); } decl_specs->storage_class = storage_class; + set_and_check_decl_spec_loc (decl_specs, ds_storage_class, location); /* A storage class specifier cannot be applied alongside a typedef specifier. If there is a typedef specifier present then set conflicting_specifiers_p which will trigger an error later on in grokdeclarator. */ - if (decl_specs->specs[(int)ds_typedef]) + if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)) decl_specs->conflicting_specifiers_p = true; } @@ -22083,24 +22050,27 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs, this is what happened. In system headers, we ignore these declarations so that G++ can work with system headers that are not C++-safe. */ - if (decl_specs->specs[(int) ds_typedef] + if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef) && !type_definition_p && (type_spec == boolean_type_node || type_spec == char16_type_node || type_spec == char32_type_node || type_spec == wchar_type_node) && (decl_specs->type - || decl_specs->specs[(int) ds_long] - || decl_specs->specs[(int) ds_short] - || decl_specs->specs[(int) ds_unsigned] - || decl_specs->specs[(int) ds_signed])) + || decl_spec_seq_has_spec_p (decl_specs, ds_long) + || decl_spec_seq_has_spec_p (decl_specs, ds_short) + || decl_spec_seq_has_spec_p (decl_specs, ds_unsigned) + || decl_spec_seq_has_spec_p (decl_specs, ds_signed))) { decl_specs->redefined_builtin_type = type_spec; + set_and_check_decl_spec_loc (decl_specs, + ds_redefined_builtin_type_spec, + location); if (!decl_specs->type) { decl_specs->type = type_spec; decl_specs->type_definition_p = false; - decl_specs->type_location = location; + set_and_check_decl_spec_loc (decl_specs,ds_type_spec, location); } } else if (decl_specs->type) @@ -22110,17 +22080,96 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs, decl_specs->type = type_spec; decl_specs->type_definition_p = type_definition_p; decl_specs->redefined_builtin_type = NULL_TREE; - decl_specs->type_location = location; + set_and_check_decl_spec_loc (decl_specs, ds_type_spec, location); + } +} + +/* Set the location for a declarator specifier and check if it is + duplicated. + + DECL_SPECS is the sequence of declarator specifiers onto which to + set the location. + + DS is the single declarator specifier to set which location is to + be set onto the existing sequence of declarators. + + LOCATION is the location for the declarator specifier to + consider. */ + +static void +set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs, + cp_decl_spec ds, source_location location) +{ + gcc_assert (ds < ds_last); + + if (decl_specs == NULL) + return; + + if (decl_specs->locations[ds] == 0) + decl_specs->locations[ds] = location; + else + { + if (ds == ds_long) + { + if (decl_specs->locations[ds_long_long] != 0) + error_at (location, + "% is too long for GCC"); + else + { + decl_specs->locations[ds_long_long] = location; + pedwarn_cxx98 (location, + OPT_Wlong_long, + "ISO C++ 1998 does not support %"); + } + } + else + { + static const char *const decl_spec_names[] = { + "signed", + "unsigned", + "short", + "long", + "const", + "volatile", + "restrict", + "inline", + "virtual", + "explicit", + "friend", + "typedef", + "using", + "constexpr", + "__complex", + "__thread" + }; + error_at (location, + "duplicate %qs", decl_spec_names[ds]); + } } } +/* Return true iff the declarator specifier DS is present in the + sequence of declarator specifiers DECL_SPECS. */ + +bool +decl_spec_seq_has_spec_p (const cp_decl_specifier_seq * decl_specs, + cp_decl_spec ds) +{ + gcc_assert (ds < ds_last); + + if (decl_specs == NULL) + return false; + + return decl_specs->locations[ds] != 0; +} + /* DECL_SPECIFIERS is the representation of a decl-specifier-seq. Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */ static bool cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers) { - return decl_specifiers->specs[(int) ds_friend] != 0; + return decl_spec_seq_has_spec_p (decl_specifiers, ds_friend); } /* Issue an error message indicating that TOKEN_DESC was expected. @@ -23933,17 +23982,17 @@ cp_parser_objc_class_ivars (cp_parser* parser) } /* __thread. */ - if (declspecs.specs[(int) ds_thread]) + if (decl_spec_seq_has_spec_p (&declspecs, ds_thread)) { cp_parser_error (parser, "invalid type for instance variable"); - declspecs.specs[(int) ds_thread] = 0; + declspecs.locations[ds_thread] = 0; } /* typedef. */ - if (declspecs.specs[(int) ds_typedef]) + if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef)) { cp_parser_error (parser, "invalid type for instance variable"); - declspecs.specs[(int) ds_typedef] = 0; + declspecs.locations[ds_thread] = 0; } prefix_attributes = declspecs.attributes; @@ -24512,17 +24561,17 @@ cp_parser_objc_struct_declaration (cp_parser *parser) } /* __thread. */ - if (declspecs.specs[(int) ds_thread]) + if (decl_spec_seq_has_spec_p (&declspecs, ds_thread)) { cp_parser_error (parser, "invalid type for property"); - declspecs.specs[(int) ds_thread] = 0; + declspecs.locations[ds_thread] = 0; } /* typedef. */ - if (declspecs.specs[(int) ds_typedef]) + if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef)) { cp_parser_error (parser, "invalid type for property"); - declspecs.specs[(int) ds_typedef] = 0; + declspecs.locations[ds_typedef] = 0; } prefix_attributes = declspecs.attributes; diff --git a/gcc/testsuite/g++.dg/cpp/syshdr3.C b/gcc/testsuite/g++.dg/cpp/syshdr3.C new file mode 100644 index 0000000..3916823 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp/syshdr3.C @@ -0,0 +1,16 @@ +/* Contributed by Dodji Seketeli */ +/* Origin: PR preprocessor/7263 */ +/* { dg-options "-pedantic -std=c++98 -ftrack-macro-expansion=1" } */ +/* { dg-do compile } */ + +/* This tests the proprer suppression of warning coming from macro + defined in system headers and expanded in a non-system header + location. */ +#include "syshdr3.h" + +static _Complex float c = _Complex_I + _Complex_I; /* These macros are defined in + system header so we should + have no warning here. */ +U_LL u = ONE_ULL; /* Likewise here. */ + +unsigned long long v = 1ULL; /* { dg-warning "long long" } */ diff --git a/gcc/testsuite/g++.dg/cpp/syshdr3.h b/gcc/testsuite/g++.dg/cpp/syshdr3.h new file mode 100644 index 0000000..e5d502a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp/syshdr3.h @@ -0,0 +1,7 @@ +#pragma GCC system_header + +#define _Complex __complex__ +#define _Complex_I 1.0iF + +#define U_LL unsigned long long +#define ONE_ULL 1ULL diff --git a/gcc/testsuite/g++.dg/system-binary-constants-1.C b/gcc/testsuite/g++.dg/system-binary-constants-1.C new file mode 100644 index 0000000..7ef26f7 --- /dev/null +++ b/gcc/testsuite/g++.dg/system-binary-constants-1.C @@ -0,0 +1,18 @@ +/* + Origin: Dodji Seketeli + { dg-options "-std=c++98 -pedantic" } + { dg-do compile } + */ + +#include "system-binary-constants-1.h" + +int +foo (void) +{ +#if BINARY_INT_CONSTANT_IN_SYSTEM_HEADER /* A binary constant defined + in system header. No + warning. */ + return 23; +#endif + return 0b1101; /* { dg-warning "binary constants are a GCC extension" } */ +} diff --git a/gcc/testsuite/g++.dg/system-binary-constants-1.h b/gcc/testsuite/g++.dg/system-binary-constants-1.h new file mode 100644 index 0000000..85f2917 --- /dev/null +++ b/gcc/testsuite/g++.dg/system-binary-constants-1.h @@ -0,0 +1,3 @@ +#pragma GCC system_header + +#define BINARY_INT_CONSTANT_IN_SYSTEM_HEADER 0b1101 diff --git a/gcc/testsuite/gcc.dg/binary-constants-2.c b/gcc/testsuite/gcc.dg/binary-constants-2.c index 40d7636..6c3928a 100644 --- a/gcc/testsuite/gcc.dg/binary-constants-2.c +++ b/gcc/testsuite/gcc.dg/binary-constants-2.c @@ -2,7 +2,7 @@ /* Origin: Joerg Wunsch . */ /* { dg-do compile } */ -/* { dg-options "-std=iso9899:1999 -pedantic" } */ +/* { dg-options "-std=iso9899:1999 -pedantic -ftrack-macro-expansion=0" } */ #define FOO 0b1101 diff --git a/gcc/testsuite/gcc.dg/binary-constants-3.c b/gcc/testsuite/gcc.dg/binary-constants-3.c index 984477d..410fc4c 100644 --- a/gcc/testsuite/gcc.dg/binary-constants-3.c +++ b/gcc/testsuite/gcc.dg/binary-constants-3.c @@ -2,7 +2,7 @@ /* Origin: Joerg Wunsch . */ /* { dg-do compile } */ -/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */ +/* { dg-options "-std=iso9899:1999 -pedantic-errors -ftrack-macro-expansion=0" } */ #define FOO 0b1101 diff --git a/gcc/testsuite/gcc.dg/cpp/pr7263-3.c b/gcc/testsuite/gcc.dg/cpp/pr7263-3.c index efa619a..225b659 100644 --- a/gcc/testsuite/gcc.dg/cpp/pr7263-3.c +++ b/gcc/testsuite/gcc.dg/cpp/pr7263-3.c @@ -1,6 +1,6 @@ /* PR 7263: __extension__ keyword doesn't suppress warning on LL or ULL constants. */ /* { dg-do compile } */ -/* { dg-options "-std=c99 -pedantic-errors" } */ +/* { dg-options "-std=c99 -pedantic-errors -ftrack-macro-expansion=0" } */ #include "pr7263-3.h" __complex__ bar () /* { dg-error "ISO C does not support plain .complex. meaning .double complex." } */ { diff --git a/gcc/testsuite/gcc.dg/cpp/syshdr3.c b/gcc/testsuite/gcc.dg/cpp/syshdr3.c new file mode 100644 index 0000000..15749ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/syshdr3.c @@ -0,0 +1,16 @@ +/* Contributed by Dodji Seketeli */ +/* Origin: PR preprocessor/7263 */ +/* { dg-options "-pedantic -std=c89 -ftrack-macro-expansion=1" } */ +/* { dg-do compile } */ + +/* This tests the proprer suppression of warning coming from macro + defined in system headers and expanded in a non-system header + location. */ +#include "syshdr3.h" + +static _Complex float c = _Complex_I + _Complex_I; /* These macros are defined in + system header so we should + have no warning here. */ +U_LL u = ONE_ULL; /* Likewise here. */ + +unsigned long long v = 1ULL; /* { dg-warning "long long" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/syshdr3.h b/gcc/testsuite/gcc.dg/cpp/syshdr3.h new file mode 100644 index 0000000..e5d502a --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/syshdr3.h @@ -0,0 +1,7 @@ +#pragma GCC system_header + +#define _Complex __complex__ +#define _Complex_I 1.0iF + +#define U_LL unsigned long long +#define ONE_ULL 1ULL diff --git a/gcc/testsuite/gcc.dg/cpp/sysmac1.c b/gcc/testsuite/gcc.dg/cpp/sysmac1.c index fa741a4..cc8469e 100644 --- a/gcc/testsuite/gcc.dg/cpp/sysmac1.c +++ b/gcc/testsuite/gcc.dg/cpp/sysmac1.c @@ -1,7 +1,7 @@ /* Copyright (C) 2001 Free Software Foundation, Inc. */ /* { dg-do preprocess } */ -/* { dg-options "-std=gnu99 -pedantic -Wtraditional" } */ +/* { dg-options "-std=gnu99 -pedantic -Wtraditional -ftrack-macro-expansion=0" } */ /* Tests diagnostics are suppressed for some macros defined in system headers. */ diff --git a/gcc/testsuite/gcc.dg/cpp/sysmac2.c b/gcc/testsuite/gcc.dg/cpp/sysmac2.c index 6d493a9..cdba668 100644 --- a/gcc/testsuite/gcc.dg/cpp/sysmac2.c +++ b/gcc/testsuite/gcc.dg/cpp/sysmac2.c @@ -1,7 +1,7 @@ /* Copyright (C) 2001 Free Software Foundation, Inc. */ /* { dg-do compile } */ -/* { dg-options "-std=gnu99 -pedantic -Wtraditional" } */ +/* { dg-options "-std=gnu99 -pedantic -Wtraditional -ftrack-macro-expansion=0" } */ /* Tests diagnostics are suppressed for some macros defined in system headers. */ diff --git a/gcc/testsuite/gcc.dg/nofixed-point-2.c b/gcc/testsuite/gcc.dg/nofixed-point-2.c index 5b2f209..8442a19 100644 --- a/gcc/testsuite/gcc.dg/nofixed-point-2.c +++ b/gcc/testsuite/gcc.dg/nofixed-point-2.c @@ -20,10 +20,10 @@ f3 (void) return 0k; /* { dg-error "not supported" "reject fixed-point" } */ } -_Sat -f4 (void) /* { dg-error "not supported" "reject fixed-point" } */ +_Sat /* { dg-error "not supported" "reject fixed-point" } */ +f4 (void) { return 0k; /* { dg-error "not supported" "reject fixed-point" } */ } -/* { dg-error "is used without" "" { target *-*-* } 24 } */ +/* { dg-error "is used without" "" { target *-*-* } 23 } */ diff --git a/gcc/testsuite/gcc.dg/system-binary-constants-1.c b/gcc/testsuite/gcc.dg/system-binary-constants-1.c new file mode 100644 index 0000000..921ee20 --- /dev/null +++ b/gcc/testsuite/gcc.dg/system-binary-constants-1.c @@ -0,0 +1,18 @@ +/* + Origin: Dodji Seketeli + { dg-options "-std=iso9899:1999 -pedantic" } + { dg-do compile } + */ + +#include "system-binary-constants-1.h" + +int +foo (void) +{ +#if BINARY_INT_CONSTANT_IN_SYSTEM_HEADER /* A binary constant defined + in system header. No + warning. */ + return 23; +#endif + return 0b1101; /* { dg-warning "binary constants are a GCC extension" } */ +} diff --git a/gcc/testsuite/gcc.dg/system-binary-constants-1.h b/gcc/testsuite/gcc.dg/system-binary-constants-1.h new file mode 100644 index 0000000..85f2917 --- /dev/null +++ b/gcc/testsuite/gcc.dg/system-binary-constants-1.h @@ -0,0 +1,3 @@ +#pragma GCC system_header + +#define BINARY_INT_CONSTANT_IN_SYSTEM_HEADER 0b1101 diff --git a/libcpp/expr.c b/libcpp/expr.c index d56e56a..41c9880 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -59,7 +59,7 @@ static cpp_num num_rshift (cpp_num, size_t, size_t); static cpp_num append_digit (cpp_num, int, int, size_t); static cpp_num parse_defined (cpp_reader *); -static cpp_num eval_token (cpp_reader *, const cpp_token *); +static cpp_num eval_token (cpp_reader *, const cpp_token *, source_location); static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype); static unsigned int interpret_float_suffix (const uchar *, size_t); static unsigned int interpret_int_suffix (const uchar *, size_t); @@ -76,6 +76,12 @@ static void check_promotion (cpp_reader *, const struct op *); #define SYNTAX_ERROR2(msgid, arg) \ do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \ while(0) +#define SYNTAX_ERROR_AT(loc, msgid) \ + do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid); goto syntax_error; } \ + while(0) +#define SYNTAX_ERROR2_AT(loc, msgid, arg) \ + do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid, arg); goto syntax_error; } \ + while(0) /* Subroutine of cpp_classify_number. S points to a float suffix of length LEN, possibly zero. Returns 0 for an invalid suffix, or a @@ -358,11 +364,18 @@ cpp_get_userdef_suffix (const cpp_token *tok) /* Categorize numeric constants according to their field (integer, floating point, or invalid), radix (decimal, octal, hexadecimal), - and type suffixes. In C++0X if UD_SUFFIX is non null it will be - assigned any unrecognized suffix for a user-defined literal. */ + and type suffixes. + + TOKEN is the token that represents the numeric constant to + classify. + + In C++0X if UD_SUFFIX is non null it will be assigned + any unrecognized suffix for a user-defined literal. + + VIRTUAL_LOCATION is the virtual location for TOKEN. */ unsigned int cpp_classify_number (cpp_reader *pfile, const cpp_token *token, - const char **ud_suffix) + const char **ud_suffix, source_location virtual_location) { const uchar *str = token->val.str.text; const uchar *limit; @@ -421,7 +434,8 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, if (float_flag == NOT_FLOAT) float_flag = AFTER_POINT; else - SYNTAX_ERROR ("too many decimal points in number"); + SYNTAX_ERROR_AT (virtual_location, + "too many decimal points in number"); } else if ((radix <= 10 && (c == 'e' || c == 'E')) || (radix == 16 && (c == 'p' || c == 'P'))) @@ -449,8 +463,8 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, radix = 10; if (CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "fixed-point constants are a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "fixed-point constants are a GCC extension"); goto syntax_ok; } else @@ -463,26 +477,29 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, if (max_digit >= radix) { if (radix == 2) - SYNTAX_ERROR2 ("invalid digit \"%c\" in binary constant", '0' + max_digit); + SYNTAX_ERROR2_AT (virtual_location, + "invalid digit \"%c\" in binary constant", '0' + max_digit); else - SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit); + SYNTAX_ERROR2_AT (virtual_location, + "invalid digit \"%c\" in octal constant", '0' + max_digit); } if (float_flag != NOT_FLOAT) { if (radix == 2) { - cpp_error (pfile, CPP_DL_ERROR, - "invalid prefix \"0b\" for floating constant"); + cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0, + "invalid prefix \"0b\" for floating constant"); return CPP_N_INVALID; } if (radix == 16 && !seen_digit) - SYNTAX_ERROR ("no digits in hexadecimal floating constant"); + SYNTAX_ERROR_AT (virtual_location, + "no digits in hexadecimal floating constant"); if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99)) - cpp_error (pfile, CPP_DL_PEDWARN, - "use of C99 hexadecimal floating constant"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "use of C99 hexadecimal floating constant"); if (float_flag == AFTER_EXPON) { @@ -491,14 +508,15 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, /* Exponent is decimal, even if string is a hex float. */ if (!ISDIGIT (*str)) - SYNTAX_ERROR ("exponent has no digits"); + SYNTAX_ERROR_AT (virtual_location, "exponent has no digits"); do str++; while (ISDIGIT (*str)); } else if (radix == 16) - SYNTAX_ERROR ("hexadecimal floating constants require an exponent"); + SYNTAX_ERROR_AT (virtual_location, + "hexadecimal floating constants require an exponent"); result = interpret_float_suffix (str, limit - str); if (result == 0) @@ -511,9 +529,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, } else { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" on floating constant", - (int) (limit - str), str); + cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0, + "invalid suffix \"%.*s\" on floating constant", + (int) (limit - str), str); return CPP_N_INVALID; } } @@ -522,33 +540,33 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, if (limit != str && CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile)) - cpp_warning (pfile, CPP_W_TRADITIONAL, - "traditional C rejects the \"%.*s\" suffix", - (int) (limit - str), str); + cpp_warning_with_line (pfile, CPP_W_TRADITIONAL, virtual_location, 0, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); /* A suffix for double is a GCC extension via decimal float support. If the suffix also specifies an imaginary value we'll catch that later. */ if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "suffix for double constant is a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "suffix for double constant is a GCC extension"); /* Radix must be 10 for decimal floats. */ if ((result & CPP_N_DFLOAT) && radix != 10) { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" with hexadecimal floating constant", - (int) (limit - str), str); + cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0, + "invalid suffix \"%.*s\" with hexadecimal floating constant", + (int) (limit - str), str); return CPP_N_INVALID; } if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "fixed-point constants are a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "fixed-point constants are a GCC extension"); if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "decimal float constants are a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "decimal float constants are a GCC extension"); result |= CPP_N_FLOATING; } @@ -565,9 +583,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, } else { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" on integer constant", - (int) (limit - str), str); + cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0, + "invalid suffix \"%.*s\" on integer constant", + (int) (limit - str), str); return CPP_N_INVALID; } } @@ -581,9 +599,10 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, && CPP_OPTION (pfile, cpp_warn_long_long); if (u_or_i || large) - cpp_warning (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL, - "traditional C rejects the \"%.*s\" suffix", - (int) (limit - str), str); + cpp_warning_with_line (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL, + virtual_location, 0, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); } if ((result & CPP_N_WIDTH) == CPP_N_LARGE @@ -594,9 +613,11 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, : N_("use of C99 long long integer constant"); if (CPP_OPTION (pfile, c99)) - cpp_warning (pfile, CPP_W_LONG_LONG, message); + cpp_warning_with_line (pfile, CPP_W_LONG_LONG, virtual_location, + 0, message); else - cpp_pedwarning (pfile, CPP_W_LONG_LONG, message); + cpp_pedwarning_with_line (pfile, CPP_W_LONG_LONG, + virtual_location, 0, message); } result |= CPP_N_INTEGER; @@ -604,11 +625,11 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, syntax_ok: if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "imaginary constants are a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "imaginary constants are a GCC extension"); if (radix == 2 && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "binary constants are a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, + "binary constants are a GCC extension"); if (radix == 10) result |= CPP_N_DECIMAL; @@ -896,7 +917,8 @@ parse_defined (cpp_reader *pfile) number or character constant, or the result of the "defined" or "#" operators). */ static cpp_num -eval_token (cpp_reader *pfile, const cpp_token *token) +eval_token (cpp_reader *pfile, const cpp_token *token, + source_location virtual_location) { cpp_num result; unsigned int temp; @@ -908,21 +930,21 @@ eval_token (cpp_reader *pfile, const cpp_token *token) switch (token->type) { case CPP_NUMBER: - temp = cpp_classify_number (pfile, token, NULL); + temp = cpp_classify_number (pfile, token, NULL, virtual_location); if (temp & CPP_N_USERDEF) cpp_error (pfile, CPP_DL_ERROR, "user-defined literal in preprocessor expression"); switch (temp & CPP_N_CATEGORY) { case CPP_N_FLOATING: - cpp_error (pfile, CPP_DL_ERROR, - "floating constant in preprocessor expression"); + cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0, + "floating constant in preprocessor expression"); break; case CPP_N_INTEGER: if (!(temp & CPP_N_IMAGINARY)) return cpp_interpret_integer (pfile, token, temp); - cpp_error (pfile, CPP_DL_ERROR, - "imaginary number in preprocessor expression"); + cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0, + "imaginary number in preprocessor expression"); break; case CPP_N_INVALID: @@ -969,8 +991,9 @@ eval_token (cpp_reader *pfile, const cpp_token *token) result.high = 0; result.low = 0; if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) - cpp_warning (pfile, CPP_W_UNDEF, "\"%s\" is not defined", - NODE_NAME (token->val.node.node)); + cpp_warning_with_line (pfile, CPP_W_UNDEF, virtual_location, 0, + "\"%s\" is not defined", + NODE_NAME (token->val.node.node)); } break; @@ -980,11 +1003,12 @@ eval_token (cpp_reader *pfile, const cpp_token *token) /* A pedantic warning takes precedence over a deprecated warning here. */ if (CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "assertions are a GCC extension"); + cpp_error_with_line (pfile, CPP_DL_PEDWARN, + virtual_location, 0, + "assertions are a GCC extension"); else if (CPP_OPTION (pfile, cpp_warn_deprecated)) - cpp_warning (pfile, CPP_W_DEPRECATED, - "assertions are a deprecated extension"); + cpp_warning_with_line (pfile, CPP_W_DEPRECATED, virtual_location, 0, + "assertions are a deprecated extension"); } _cpp_test_assertion (pfile, &temp); result.high = 0; @@ -1086,6 +1110,7 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) struct op *top = pfile->op_stack; unsigned int lex_count; bool saw_leading_not, want_value = true; + source_location virtual_location = 0; pfile->state.skip_eval = 0; @@ -1102,9 +1127,9 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) struct op op; lex_count++; - op.token = cpp_get_token (pfile); + op.token = cpp_get_token_with_location (pfile, &virtual_location); op.op = op.token->type; - op.loc = op.token->src_loc; + op.loc = virtual_location; switch (op.op) { @@ -1117,10 +1142,11 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) case CPP_NAME: case CPP_HASH: if (!want_value) - SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", - cpp_token_as_text (pfile, op.token)); + SYNTAX_ERROR2_AT (op.loc, + "missing binary operator before token \"%s\"", + cpp_token_as_text (pfile, op.token)); want_value = false; - top->value = eval_token (pfile, op.token); + top->value = eval_token (pfile, op.token, op.loc); continue; case CPP_NOT: @@ -1137,8 +1163,9 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) default: if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ) - SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions", - cpp_token_as_text (pfile, op.token)); + SYNTAX_ERROR2_AT (op.loc, + "token \"%s\" is not valid in preprocessor expressions", + cpp_token_as_text (pfile, op.token)); break; } @@ -1146,27 +1173,32 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) if (optab[op.op].flags & NO_L_OPERAND) { if (!want_value) - SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", - cpp_token_as_text (pfile, op.token)); + SYNTAX_ERROR2_AT (op.loc, + "missing binary operator before token \"%s\"", + cpp_token_as_text (pfile, op.token)); } else if (want_value) { /* We want a number (or expression) and haven't got one. Try to emit a specific diagnostic. */ if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN) - SYNTAX_ERROR ("missing expression between '(' and ')'"); + SYNTAX_ERROR_AT (op.loc, + "missing expression between '(' and ')'"); if (op.op == CPP_EOF && top->op == CPP_EOF) - SYNTAX_ERROR2 ("%s with no expression", is_if ? "#if" : "#elif"); + SYNTAX_ERROR2_AT (op.loc, + "%s with no expression", is_if ? "#if" : "#elif"); if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) - SYNTAX_ERROR2 ("operator '%s' has no right operand", - cpp_token_as_text (pfile, top->token)); + SYNTAX_ERROR2_AT (op.loc, + "operator '%s' has no right operand", + cpp_token_as_text (pfile, top->token)); else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF) /* Complain about missing paren during reduction. */; else - SYNTAX_ERROR2 ("operator '%s' has no left operand", - cpp_token_as_text (pfile, op.token)); + SYNTAX_ERROR2_AT (op.loc, + "operator '%s' has no left operand", + cpp_token_as_text (pfile, op.token)); } top = reduce (pfile, top, op.op); @@ -1191,7 +1223,8 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) break; case CPP_COLON: if (top->op != CPP_QUERY) - SYNTAX_ERROR (" ':' without preceding '?'"); + SYNTAX_ERROR_AT (op.loc, + " ':' without preceding '?'"); if (!num_zerop (top[-1].value)) /* Was '?' condition true? */ pfile->state.skip_eval++; else @@ -1208,7 +1241,7 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) top->op = op.op; top->token = op.token; - top->loc = op.token->src_loc; + top->loc = op.loc; } /* The controlling macro expression is only valid if we called lex 3 @@ -1219,8 +1252,9 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) if (top != pfile->op_stack) { - cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in %s", - is_if ? "#if" : "#elif"); + cpp_error_with_line (pfile, CPP_DL_ICE, top->loc, 0, + "unbalanced stack in %s", + is_if ? "#if" : "#elif"); syntax_error: return false; /* Return false on syntax error. */ } diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 9dbc477..2ec7eaa 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -851,7 +851,7 @@ struct cpp_num /* Classify a CPP_NUMBER token. The return value is a combination of the flags from the above sets. */ extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *, - const char **); + const char **, source_location); /* Return the classification flags for a float suffix. */ extern unsigned int cpp_interpret_float_suffix (const char *, size_t);