From patchwork Mon Oct 15 14:37:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 984241 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-487575-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="YGH2HnbQ"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=armh.onmicrosoft.com header.i=@armh.onmicrosoft.com header.b="Rn+4H58H"; dkim-atps=neutral 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 42Ygyp6lSSz9s47 for ; Tue, 16 Oct 2018 01:37:54 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:references:date:in-reply-to:message-id :mime-version:content-type; q=dns; s=default; b=PEW7lu/AxLxvOj1q Mnssd+3MIhtaENgglwZ29aoaNWODemYwvqr8Elj9J+KC1hNrHW1cisikAXUm3FLs HIqohZ8dDJMd3XcIQTum/GdRRw/zDroyOslyAL88gd9a/9FZgysKjbDwSKl8nPxD bevMck0Df6oD9xemSm3iKtAjX4Q= 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:from :to:cc:subject:references:date:in-reply-to:message-id :mime-version:content-type; s=default; bh=4q/lo03IS/70BHe+qlt9r7 inF5U=; b=YGH2HnbQ2IeZheNZp7Z37MeCO5fwsRYtFtojv0/6THwczQTjtRPdMf YCTva9G2KGJVFr6eJ5vaVzLhUzfIMcxGE/Eh95vchcMAUDRK4DpPY2Gg+sJkEubj HZHWVYqah6oqjbhH6AbyE90HKAo/LCrlQGQYAthCHgiHN1roISMr4= Received: (qmail 64219 invoked by alias); 15 Oct 2018 14:37:45 -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 64203 invoked by uid 89); 15 Oct 2018 14:37:44 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 spammy=Statement, tre X-HELO: EUR04-HE1-obe.outbound.protection.outlook.com Received: from mail-eopbgr70040.outbound.protection.outlook.com (HELO EUR04-HE1-obe.outbound.protection.outlook.com) (40.107.7.40) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 15 Oct 2018 14:37:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector1-arm-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=eAVnXFw5f6JnEn4U6jbH2+XJQFG1mbtW6Gmg9rfuOs4=; b=Rn+4H58HttI05PPr2RBP5ZPTkTwZLhsATvfs0WQU4MOiHQ9+5dlPr2kWvN2AtGrlhQ3Y8crgZqZg/qu8hHNG89Kp6wqdoSAEGhpJ2Y6/icAFfswKRhGkXkBqQD9JGUR4M7KfJqdHYFD+7mwfykfcc+Up/SpZCQKSC/mhkMmAunA= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Richard.Sandiford@arm.com; Received: from localhost (217.140.106.32) by AM6PR08MB3254.eurprd08.prod.outlook.com (2603:10a6:209:47::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1228.25; Mon, 15 Oct 2018 14:37:33 +0000 From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, joseph@codesourcery.com, jason@redhat.com, nathan@acm.org, nd@arm.com, richard.sandiford@arm.com Cc: joseph@codesourcery.com, jason@redhat.com, nathan@acm.org, nd@arm.com Subject: [09/10] C support for sizeless types References: <87d0sbjn97.fsf@arm.com> Date: Mon, 15 Oct 2018 15:37:31 +0100 In-Reply-To: <87d0sbjn97.fsf@arm.com> (Richard Sandiford's message of "Mon, 15 Oct 2018 15:30:28 +0100") Message-ID: <877eiji8d0.fsf@arm.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) MIME-Version: 1.0 Received-SPF: None (protection.outlook.com: arm.com does not designate permitted sender hosts) This patch adds support for sizeless types to C, along the lines described in the covering RFC. The patch is actually a squash of 26 patches that I've attached as a tarball, with each patch building up the support piece-by-piece. The individual patches say which part of the standard they relate to and add associated tests to gcc.dg/sizeless-1.c. 2018-10-15 Richard Sandiford gcc/c-family/ * c-common.h (RID_SIZELESS_STRUCT): New rid enum. (DEFINITE_OR_VOID_TYPE_P): New macro. (DEFINITE_OR_UNBOUND_ARRAY_TYPE_P): Likewise. * c-common.c (c_common_reswords): Add __sizeless_struct. (complete_size_in_bytes): New function. (pointer_int_sum): Use it instead of size_in_bytes_loc. (c_alignof_expr): Pass sizeless types directly to c_alignof. gcc/c/ * c-tree.h (C_TYPE_INCOMPLETE_VARS): Rename to... (C_TYPE_INDEFINITE_VARS): ...this. (start_struct, parser_xref_tag): Add a bool parameter. (require_complete_type): Add a default false parameter. (require_definite_type): New function. * c-decl.c (pushdecl): Use DEFINITE_TYPE_P instead of COMPLETE_TYPE_P. Update after above name change. (lookup_tag): Add a sizeless_p parameter. Check that it matches the TYPE_SIZELESS_P field of any existing type with the same name. (shadow_tag_warned): Update call accordingly. (start_decl): Require variables to have definite rather than complete type. Don't reject initializers for variable-sized objects with sizeless type. (finish_decl): Reject sizeless objects with static or thread-local storage duration. (build_compound_literal): Require compound literals to have definite rather than complete type. (grokdeclarator): Likewise fields. (grokparms): Likewise function parameters. (parser_xref_tag): Add a sizeless_p parameter. Update call to lookup_tag. Initialize TYPE_SIZELESS_P when creating a new type. (start_struct): Likewise. (xref_tag): Update call to parser_xref_tag. (finish_struct): Reject flexible array members in sizeless structures. Reject sizeless fields in sized aggregates. Update after above name change. (start_enum): Update call to lookup_tag. (start_function): Require the return type to be definite rather than complete. (store_parm_decls_oldstyle): Likewise function parameters. * c-parser.c (c_parser_declspecs): Handle RID_SIZELESS_STRUCT. (c_parser_struct_or_union_specifier): Likewise. Update calls to start_struct and parser_xref_tag. (c_parser_enum_specifier): Update call to parser_xref_tag. (c_parser_generic_selection): Require the type in a _Generic association to be definite rather than complete. (c_parser_objc_selector): Handle RID_SIZELESS_STRUCT (but commented out). (c_parser_omp_threadprivate): Add a comment. * c-typeck.c (require_complete_type): Add an allow_sizeless_p parameter. (default_conversion): Require the type to be definite rather than complete when processing the expression being converted. (build_component_ref): Likewise when processing member accesses. (build_indirect_ref): Likewise when processing pointer dereferences. (build_function_call_vec): Likewise when processing the return type of a function call. (convert_arguments): Likewise when processing the types of the formal and actual parameters. (build_unary_op): Likewise when processing the operand of a unary operation. (build_c_cast): Likewise when processing the value being cast. (build_modify_expr): Likewise when processing the lhs of an assignment. (convert_for_assignment): Likewise when processing the rhs of an assignment. (c_process_expr_stmt): Likewise when processing the type of a statement expression. (c_build_va_arg): Likewise when processing the second argument of a va_arg call. (c_build_qualified_type): Update after above name change. gcc/objc/ * objc-runtime-shared-support.c (objc_start_struct): Update call to start_struct. gcc/objcp/ * objcp-decl.h (start_struct): Add a sizeless_p parameter. gcc/testsuite/ * gcc.dg/sizeless-1.c: New test. Index: gcc/c-family/c-common.h =================================================================== --- gcc/c-family/c-common.h 2018-10-15 14:13:28.592266684 +0100 +++ gcc/c-family/c-common.h 2018-10-15 14:13:32.988230244 +0100 @@ -104,6 +104,7 @@ enum rid RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, RID_BUILTIN_TGMATH, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, + RID_SIZELESS_STRUCT, /* TS 18661-3 keywords, in the same sequence as the TI_* values. */ RID_FLOAT16, @@ -750,10 +751,18 @@ #define C_TYPE_OBJECT_OR_INCOMPLETE_P(ty #define COMPLETE_OR_VOID_TYPE_P(NODE) \ (COMPLETE_TYPE_P (NODE) || VOID_TYPE_P (NODE)) +/* Nonzero if this type is definite or is cv void. */ +#define DEFINITE_OR_VOID_TYPE_P(NODE) \ + (DEFINITE_TYPE_P (NODE) || VOID_TYPE_P (NODE)) + /* Nonzero if this type is complete or is an array with unspecified bound. */ #define COMPLETE_OR_UNBOUND_ARRAY_TYPE_P(NODE) \ (COMPLETE_TYPE_P (TREE_CODE (NODE) == ARRAY_TYPE ? TREE_TYPE (NODE) : (NODE))) +/* Nonzero if this type is definite or is an array with unspecified bound. */ +#define DEFINITE_OR_UNBOUND_ARRAY_TYPE_P(NODE) \ + (DEFINITE_TYPE_P (TREE_CODE (NODE) == ARRAY_TYPE ? TREE_TYPE (NODE) : (NODE))) + /* Return true if the argument is a complete type or an array of unknown bound (whose type is incomplete but) whose elements have complete type. */ Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c 2018-10-15 14:08:44.946617301 +0100 +++ gcc/c-family/c-common.c 2018-10-15 14:13:32.988230244 +0100 @@ -425,6 +425,7 @@ const struct c_common_resword c_common_r { "__restrict__", RID_RESTRICT, 0 }, { "__signed", RID_SIGNED, 0 }, { "__signed__", RID_SIGNED, 0 }, + { "__sizeless_struct", RID_SIZELESS_STRUCT, 0 }, { "__thread", RID_THREAD, 0 }, { "__transaction_atomic", RID_TRANSACTION_ATOMIC, 0 }, { "__transaction_relaxed", RID_TRANSACTION_RELAXED, 0 }, @@ -3067,6 +3068,32 @@ shorten_compare (location_t loc, tree *o return NULL_TREE; } +/* Return the size nominally occupied by an object of type TYPE + when it resides in memory. The value is measured in units of bytes, + and its data type is that normally used for type sizes + (which is the first type created by make_signed_type or + make_unsigned_type). + + Return error_mark_node if TYPE is incomplete, and in addition + raise an error if COMPLAIN is true. LOC is the location to use + for reporting error messages. */ + +tree +complete_size_in_bytes (location_t loc, const_tree type, bool complain) +{ + if (type == error_mark_node) + return error_mark_node; + + if (!COMPLETE_TYPE_P (type)) + { + if (complain) + lang_hooks.types.incomplete_type_error (loc, NULL_TREE, type); + return error_mark_node; + } + + return TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type)); +} + /* Return a tree for the sum or difference (RESULTCODE says which) of pointer PTROP and integer INTOP. */ @@ -3098,7 +3125,16 @@ pointer_int_sum (location_t loc, enum tr size_exp = integer_one_node; } else - size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type)); + { + size_exp = complete_size_in_bytes (loc, TREE_TYPE (result_type), + complain); + if (size_exp == error_mark_node) + { + if (!complain) + return size_exp; + size_exp = integer_one_node; + } + } /* We are manipulating pointer values, so we don't need to warn about relying on undefined signed overflow. We disable the @@ -3663,6 +3699,10 @@ c_alignof_expr (location_t loc, tree exp { tree t; + if (TREE_TYPE (expr) != error_mark_node + && TYPE_SIZELESS_P (TREE_TYPE (expr))) + return c_alignof (loc, TREE_TYPE (expr)); + if (VAR_OR_FUNCTION_DECL_P (expr)) t = size_int (DECL_ALIGN_UNIT (expr)); Index: gcc/c/c-tree.h =================================================================== --- gcc/c/c-tree.h 2018-08-28 11:25:45.530886001 +0100 +++ gcc/c/c-tree.h 2018-10-15 14:13:32.996230178 +0100 @@ -38,9 +38,9 @@ #define C_TYPE_FIELDS_VOLATILE(TYPE) TRE nonzero if the definition of the type has already started. */ #define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE) -/* In an incomplete RECORD_TYPE or UNION_TYPE, a list of variable +/* In an indefinite RECORD_TYPE or UNION_TYPE, a list of variable declarations whose type would be completed by completing that type. */ -#define C_TYPE_INCOMPLETE_VARS(TYPE) TYPE_VFIELD (TYPE) +#define C_TYPE_INDEFINITE_VARS(TYPE) TYPE_VFIELD (TYPE) /* In an IDENTIFIER_NODE, nonzero if this identifier is actually a keyword. C_RID_CODE (node) is then the RID_* value of the keyword. */ @@ -574,14 +574,15 @@ extern tree start_enum (location_t, stru extern bool start_function (struct c_declspecs *, struct c_declarator *, tree); extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool, tree); -extern tree start_struct (location_t, enum tree_code, tree, +extern tree start_struct (location_t, enum tree_code, bool, tree, struct c_struct_parse_info **); extern void store_parm_decls (void); extern void store_parm_decls_from (struct c_arg_info *); extern void temp_store_parm_decls (tree, tree); extern void temp_pop_parm_decls (void); extern tree xref_tag (enum tree_code, tree); -extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree); +extern struct c_typespec parser_xref_tag (location_t, enum tree_code, + bool, tree); extern struct c_parm *build_c_parm (struct c_declspecs *, tree, struct c_declarator *, location_t); extern struct c_declarator *build_attrs_declarator (tree, @@ -626,7 +627,7 @@ extern bool c_vla_unspec_p (tree x, tree extern struct c_switch *c_switch_stack; extern tree c_objc_common_truthvalue_conversion (location_t, tree); -extern tree require_complete_type (location_t, tree); +extern tree require_complete_type (location_t, tree, bool = false); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); @@ -774,6 +775,19 @@ set_c_expr_source_range (c_expr *expr, /* In c-fold.c */ extern vec incomplete_record_decls; +/* Do `exp = require_definite_type (loc, exp);' to make sure exp + does not have an indefinite type; i.e. to make sure that the + definition of the type has been seen and completely processed. + Void types are always indefinite (and thus incomplete). + + LOC is the location of the use. */ + +inline tree +require_definite_type (location_t loc, tree value) +{ + return require_complete_type (loc, value, true); +} + #if CHECKING_P namespace selftest { extern void run_c_tests (void); Index: gcc/c/c-decl.c =================================================================== --- gcc/c/c-decl.c 2018-10-05 13:46:08.319810858 +0100 +++ gcc/c/c-decl.c 2018-10-15 14:13:32.992230210 +0100 @@ -3113,7 +3113,7 @@ pushdecl (tree x) slot (e.g. "f(void a, ...)") - that doesn't count as an incomplete type. */ if (TREE_TYPE (x) != error_mark_node - && !COMPLETE_TYPE_P (TREE_TYPE (x))) + && !DEFINITE_TYPE_P (TREE_TYPE (x))) { tree element = TREE_TYPE (x); @@ -3124,9 +3124,9 @@ pushdecl (tree x) if (RECORD_OR_UNION_TYPE_P (element) && (TREE_CODE (x) != TYPE_DECL || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) - && !COMPLETE_TYPE_P (element)) - C_TYPE_INCOMPLETE_VARS (element) - = tree_cons (NULL_TREE, x, C_TYPE_INCOMPLETE_VARS (element)); + && !DEFINITE_TYPE_P (element)) + C_TYPE_INDEFINITE_VARS (element) + = tree_cons (NULL_TREE, x, C_TYPE_INDEFINITE_VARS (element)); } return x; } @@ -3928,13 +3928,14 @@ c_check_switch_jump_warnings (struct c_s If THISLEVEL_ONLY is nonzero, searches only the current_scope. CODE says which kind of type the caller wants; it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + SIZELESS_P is true if the type should be sizeless rather than sized. If PLOC is not NULL and this returns non-null, it sets *PLOC to the location where the tag was defined. If the wrong kind of type is found, an error is reported. */ static tree -lookup_tag (enum tree_code code, tree name, bool thislevel_only, - location_t *ploc) +lookup_tag (enum tree_code code, bool sizeless_p, tree name, + bool thislevel_only, location_t *ploc) { struct c_binding *b = I_TAG_BINDING (name); bool thislevel = false; @@ -3944,7 +3945,9 @@ lookup_tag (enum tree_code code, tree na /* We only care about whether it's in this level if thislevel_only was set or it might be a type clash. */ - if (thislevel_only || TREE_CODE (b->decl) != code) + bool clash_p = (TREE_CODE (b->decl) != code + || TYPE_SIZELESS_P (b->decl) != sizeless_p); + if (thislevel_only || clash_p) { /* For our purposes, a tag in the external scope is the same as a tag in the file scope. (Primarily relevant to Objective-C @@ -3958,7 +3961,7 @@ lookup_tag (enum tree_code code, tree na if (thislevel_only && !thislevel) return NULL_TREE; - if (TREE_CODE (b->decl) != code) + if (clash_p) { /* Definition isn't the kind we were looking for. */ pending_invalid_xref = name; @@ -4346,6 +4349,7 @@ shadow_tag_warned (const struct c_declsp { tree value = declspecs->type; enum tree_code code = TREE_CODE (value); + bool sizeless_p = TYPE_SIZELESS_P (value); if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) /* Used to test also that TYPE_SIZE (value) != 0. @@ -4412,7 +4416,7 @@ shadow_tag_warned (const struct c_declsp else { pending_invalid_xref = NULL_TREE; - t = lookup_tag (code, name, true, NULL); + t = lookup_tag (code, sizeless_p, name, true, NULL); if (t == NULL_TREE) { @@ -4759,12 +4763,13 @@ start_decl (struct c_declarator *declara We already gave a warning, so we don't need another one. */ if (TREE_TYPE (decl) == error_mark_node) initialized = false; - else if (COMPLETE_TYPE_P (TREE_TYPE (decl))) + else if (DEFINITE_TYPE_P (TREE_TYPE (decl))) { - /* A complete type is ok if size is fixed. */ + /* A definite type is ok if size is fixed. */ - if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST - || C_DECL_VARIABLE_SIZE (decl)) + if (!TYPE_SIZELESS_P (TREE_TYPE (decl)) + && (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST + || C_DECL_VARIABLE_SIZE (decl))) { error ("variable-sized object may not be initialized"); initialized = false; @@ -5046,6 +5051,19 @@ finish_decl (tree decl, location_t init_ && COMPLETE_TYPE_P (TREE_TYPE (decl))) layout_decl (decl, 0); + if (TREE_TYPE (decl) != error_mark_node + && TYPE_SIZELESS_P (type) + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) + { + if (DECL_THREAD_LOCAL_P (decl)) + error ("sizeless variable %q+D cannot have thread-local" + " storage duration", decl); + else + error ("sizeless variable %q+D cannot have static storage" + " duration", decl); + TREE_TYPE (decl) = error_mark_node; + } + if (DECL_SIZE (decl) == NULL_TREE /* Don't give an error if we already gave one earlier. */ && TREE_TYPE (decl) != error_mark_node @@ -5384,7 +5402,7 @@ build_compound_literal (location_t loc, TREE_TYPE (DECL_INITIAL (decl)) = type; } - if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + if (type == error_mark_node || !DEFINITE_TYPE_P (type)) { c_incomplete_type_error (loc, NULL_TREE, type); return error_mark_node; @@ -6913,7 +6931,7 @@ grokdeclarator (const struct c_declarato type = build_pointer_type (type); } else if (TREE_CODE (type) != ERROR_MARK - && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type)) + && !DEFINITE_OR_UNBOUND_ARRAY_TYPE_P (type)) { if (name) error_at (loc, "field %qE has incomplete type", name); @@ -7252,7 +7270,7 @@ grokparms (struct c_arg_info *arg_info, if (type == error_mark_node) continue; - if (!COMPLETE_TYPE_P (type)) + if (!DEFINITE_TYPE_P (type)) { if (funcdef_flag) { @@ -7499,10 +7517,13 @@ get_parm_info (bool ellipsis, tree expr) /* Get the struct, enum or union (CODE says which) with tag NAME. Define the tag as a forward-reference with location LOC if it is not defined. Return a c_typespec structure for the type - specifier. */ + specifier. + + SIZELESS_P says whether the type described by CODE is sizeless. */ struct c_typespec -parser_xref_tag (location_t loc, enum tree_code code, tree name) +parser_xref_tag (location_t loc, enum tree_code code, bool sizeless_p, + tree name) { struct c_typespec ret; tree ref; @@ -7514,7 +7535,7 @@ parser_xref_tag (location_t loc, enum tr /* If a cross reference is requested, look up the type already defined for this tag and return it. */ - ref = lookup_tag (code, name, false, &refloc); + ref = lookup_tag (code, sizeless_p, name, false, &refloc); /* If this is the right type of tag, return what we found. (This reference will be shadowed by shadow_tag later if appropriate.) If this is the wrong type of tag, do not return it. If it was the @@ -7568,6 +7589,7 @@ parser_xref_tag (location_t loc, enum tr the forward-reference will be altered into a real type. */ ref = make_node (code); + TYPE_SIZELESS_P (ref) = sizeless_p; if (code == ENUMERAL_TYPE) { /* Give the type a default layout like unsigned int @@ -7594,13 +7616,15 @@ parser_xref_tag (location_t loc, enum tr tree xref_tag (enum tree_code code, tree name) { - return parser_xref_tag (input_location, code, name).spec; + /* At present, this function only needs to support sized types. */ + return parser_xref_tag (input_location, code, false, name).spec; } /* Make sure that the tag NAME is defined *in the current scope* at least as a forward reference. LOC is the location of the struct's definition. CODE says which kind of tag NAME ought to be. + SIZELESS_P says whether the associated type should be sizeless. This stores the current value of the file static STRUCT_PARSE_INFO in *ENCLOSING_STRUCT_PARSE_INFO, and points STRUCT_PARSE_INFO at a @@ -7608,7 +7632,7 @@ xref_tag (enum tree_code code, tree name STRUCT_PARSE_INFO is restored in finish_struct. */ tree -start_struct (location_t loc, enum tree_code code, tree name, +start_struct (location_t loc, enum tree_code code, bool sizeless_p, tree name, struct c_struct_parse_info **enclosing_struct_parse_info) { /* If there is already a tag defined at this scope @@ -7618,7 +7642,7 @@ start_struct (location_t loc, enum tree_ location_t refloc = UNKNOWN_LOCATION; if (name != NULL_TREE) - ref = lookup_tag (code, name, true, &refloc); + ref = lookup_tag (code, sizeless_p, name, true, &refloc); if (ref && TREE_CODE (ref) == code) { if (TYPE_STUB_DECL (ref)) @@ -7654,6 +7678,7 @@ start_struct (location_t loc, enum tree_ if (ref == NULL_TREE || TREE_CODE (ref) != code) { ref = make_node (code); + TYPE_SIZELESS_P (ref) = sizeless_p; pushtag (loc, name, ref); } @@ -8118,7 +8143,13 @@ finish_struct (location_t loc, tree t, t && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) { - if (TREE_CODE (t) == UNION_TYPE) + if (TYPE_SIZELESS_P (t)) + { + error_at (DECL_SOURCE_LOCATION (x), + "flexible array member in sizeless struct"); + TREE_TYPE (x) = error_mark_node; + } + else if (TREE_CODE (t) == UNION_TYPE) { error_at (DECL_SOURCE_LOCATION (x), "flexible array member in union"); @@ -8144,6 +8175,19 @@ finish_struct (location_t loc, tree t, t pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, "invalid use of structure with flexible array member"); + if (TREE_TYPE (x) != error_mark_node + && TYPE_SIZELESS_P (TREE_TYPE (x)) + && !TYPE_SIZELESS_P (t)) + { + if (DECL_NAME (x)) + error_at (DECL_SOURCE_LOCATION (x), + "field %qD has sizeless type", x); + else + error_at (DECL_SOURCE_LOCATION (x), + "unnamed field has sizeless type"); + TREE_TYPE (x) = error_mark_node; + } + if (DECL_NAME (x) || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) saw_named_field = true; @@ -8262,14 +8306,14 @@ finish_struct (location_t loc, tree t, t } } - /* Note: C_TYPE_INCOMPLETE_VARS overloads TYPE_VFIELD which is used + /* Note: C_TYPE_INDEFINITE_VARS overloads TYPE_VFIELD which is used in dwarf2out via rest_of_decl_compilation below and means something totally different. Since we will be clearing - C_TYPE_INCOMPLETE_VARS shortly after we iterate through them, + C_TYPE_INDEFINITE_VARS shortly after we iterate through them, clear it ahead of time and avoid problems in dwarf2out. Ideally, - C_TYPE_INCOMPLETE_VARS should use some language specific + C_TYPE_INDEFINITE_VARS should use some language specific node. */ - tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); + tree indefinite_vars = C_TYPE_INDEFINITE_VARS (TYPE_MAIN_VARIANT (t)); for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { TYPE_FIELDS (x) = TYPE_FIELDS (t); @@ -8277,7 +8321,7 @@ finish_struct (location_t loc, tree t, t C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); - C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; + C_TYPE_INDEFINITE_VARS (x) = NULL_TREE; } /* If this was supposed to be a transparent union, but we can't @@ -8300,7 +8344,7 @@ finish_struct (location_t loc, tree t, t /* If this structure or union completes the type of any previous variable declaration, lay it out and output its rtl. */ - for (x = incomplete_vars; x; x = TREE_CHAIN (x)) + for (x = indefinite_vars; x; x = TREE_CHAIN (x)) { tree decl = TREE_VALUE (x); if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) @@ -8413,7 +8457,7 @@ start_enum (location_t loc, struct c_enu forward reference. */ if (name != NULL_TREE) - enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc); + enumtype = lookup_tag (ENUMERAL_TYPE, false, name, true, &enumloc); if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) { @@ -8788,7 +8832,7 @@ start_function (struct c_declspecs *decl announce_function (decl1); - if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) + if (!DEFINITE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1)))) { error_at (loc, "return type is an incomplete type"); /* Make it return void instead. */ @@ -9141,7 +9185,7 @@ store_parm_decls_oldstyle (tree fndecl, continue; if (TREE_TYPE (parm) != error_mark_node - && !COMPLETE_TYPE_P (TREE_TYPE (parm))) + && !DEFINITE_TYPE_P (TREE_TYPE (parm))) { error_at (DECL_SOURCE_LOCATION (parm), "parameter %qD has incomplete type", parm); Index: gcc/c/c-parser.c =================================================================== --- gcc/c/c-parser.c 2018-10-05 13:46:08.319810858 +0100 +++ gcc/c/c-parser.c 2018-10-15 14:13:32.996230178 +0100 @@ -2761,6 +2761,7 @@ c_parser_declspecs (c_parser *parser, st declspecs_add_type (loc, specs, t); break; case RID_STRUCT: + case RID_SIZELESS_STRUCT: case RID_UNION: if (!typespec_ok) goto out; @@ -3023,7 +3024,7 @@ c_parser_enum_specifier (c_parser *parse ret.expr_const_operands = true; return ret; } - ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident); + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, false, ident); /* In ISO C, enumerated types can be referred to only if already defined. */ if (pedantic && !COMPLETE_TYPE_P (ret.spec)) @@ -3083,8 +3084,12 @@ c_parser_struct_or_union_specifier (c_pa location_t struct_loc; location_t ident_loc = UNKNOWN_LOCATION; enum tree_code code; + bool sizeless_p = false; switch (c_parser_peek_token (parser)->keyword) { + case RID_SIZELESS_STRUCT: + sizeless_p = true; + /* Fall through. */ case RID_STRUCT: code = RECORD_TYPE; break; @@ -3113,7 +3118,8 @@ c_parser_struct_or_union_specifier (c_pa /* Parse a struct or union definition. Start the scope of the tag before parsing components. */ struct c_struct_parse_info *struct_info; - tree type = start_struct (struct_loc, code, ident, &struct_info); + tree type = start_struct (struct_loc, code, sizeless_p, ident, + &struct_info); tree postfix_attrs; /* We chain the components in reverse order, then put them in forward order at the end. Each struct-declaration may @@ -3230,7 +3236,7 @@ c_parser_struct_or_union_specifier (c_pa ret.expr_const_operands = true; return ret; } - ret = parser_xref_tag (ident_loc, code, ident); + ret = parser_xref_tag (ident_loc, code, sizeless_p, ident); return ret; } @@ -7615,7 +7621,7 @@ c_parser_generic_selection (c_parser *pa if (TREE_CODE (assoc.type) == FUNCTION_TYPE) error_at (assoc.type_location, "%<_Generic%> association has function type"); - else if (!COMPLETE_TYPE_P (assoc.type)) + else if (!DEFINITE_TYPE_P (assoc.type)) error_at (assoc.type_location, "%<_Generic%> association has incomplete type"); @@ -10536,6 +10542,10 @@ c_parser_objc_selector (c_parser *parser { case RID_ENUM: case RID_STRUCT: +#if 0 + /* Deliberately excluded from ObjC support. */ + case RID_SIZELESS_STRUCT: +#endif case RID_UNION: case RID_IF: case RID_ELSE: @@ -18277,6 +18287,8 @@ c_parser_omp_threadprivate (c_parser *pa error_at (loc, "automatic variable %qE cannot be %", v); else if (TREE_TYPE (v) == error_mark_node) ; + /* For now we continue to require sized types here, so test + COMPLETE_TYPE_P rather than DEFINITE_TYPE_P. */ else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) error_at (loc, "% %qE has incomplete type", v); else Index: gcc/c/c-typeck.c =================================================================== --- gcc/c/c-typeck.c 2018-10-05 13:46:08.319810858 +0100 +++ gcc/c/c-typeck.c 2018-10-15 14:13:32.996230178 +0100 @@ -189,10 +189,11 @@ static void free_all_tagged_tu_seen_up_t /* Do `exp = require_complete_type (loc, exp);' to make sure exp does not have an incomplete type. (That includes void types.) - LOC is the location of the use. */ + LOC is the location of the use. ALLOW_SIZELESS_P is true if + fully-defined sizeless types are OK. */ tree -require_complete_type (location_t loc, tree value) +require_complete_type (location_t loc, tree value, bool allow_sizeless_p) { tree type = TREE_TYPE (value); @@ -200,7 +201,7 @@ require_complete_type (location_t loc, t return error_mark_node; /* First, detect a valid value with a complete type. */ - if (COMPLETE_TYPE_P (type)) + if (allow_sizeless_p ? DEFINITE_TYPE_P (type) : COMPLETE_TYPE_P (type)) return value; c_incomplete_type_error (loc, value, type); @@ -2176,7 +2177,7 @@ default_conversion (tree exp) return error_mark_node; } - exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp); + exp = require_definite_type (EXPR_LOC_OR_LOC (exp, input_location), exp); if (exp == error_mark_node) return error_mark_node; @@ -2398,7 +2399,7 @@ build_component_ref (location_t loc, tre if (code == RECORD_TYPE || code == UNION_TYPE) { - if (!COMPLETE_TYPE_P (type)) + if (!DEFINITE_TYPE_P (type)) { c_incomplete_type_error (loc, NULL_TREE, type); return error_mark_node; @@ -2548,7 +2549,7 @@ build_indirect_ref (location_t loc, tree ref = build1 (INDIRECT_REF, t, pointer); - if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE) + if (!DEFINITE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE) { if (!C_TYPE_ERROR_REPORTED (TREE_TYPE (ptr))) { @@ -3156,7 +3157,7 @@ build_function_call_vec (location_t loc, "function with qualified void return type called"); return result; } - return require_complete_type (loc, result); + return require_definite_type (loc, result); } /* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ @@ -3312,7 +3313,7 @@ convert_arguments (location_t loc, vec with reverse storage order"); return error_mark_node; } - else if (!COMPLETE_TYPE_P (type)) + else if (!DEFINITE_TYPE_P (type)) { error_at (loc2, "second argument to % is of incomplete " "type %qT", type); Index: gcc/objc/objc-runtime-shared-support.c =================================================================== --- gcc/objc/objc-runtime-shared-support.c 2018-05-02 08:37:33.373752352 +0100 +++ gcc/objc/objc-runtime-shared-support.c 2018-10-15 14:13:32.996230178 +0100 @@ -69,7 +69,8 @@ objc_start_struct (tree name) { gcc_assert (!objc_building_struct); objc_building_struct = true; - return start_struct (input_location, RECORD_TYPE, name, &objc_struct_info); + return start_struct (input_location, RECORD_TYPE, false, name, + &objc_struct_info); } /* Finish building a struct for objc. */ Index: gcc/objcp/objcp-decl.h =================================================================== --- gcc/objcp/objcp-decl.h 2018-05-02 08:37:54.209555320 +0100 +++ gcc/objcp/objcp-decl.h 2018-10-15 14:13:32.996230178 +0100 @@ -37,7 +37,7 @@ extern tree objcp_end_compound_stmt (tre invoke the original C++ functions if needed). */ #ifdef OBJCP_REMAP_FUNCTIONS -#define start_struct(loc, code, name, struct_info) \ +#define start_struct(loc, code, sizeless_p, name, struct_info) \ objcp_start_struct (loc, code, name) #define finish_struct(loc, t, fieldlist, attributes, struct_info) \ objcp_finish_struct (loc, t, fieldlist, attributes) Index: gcc/testsuite/gcc.dg/sizeless-1.c =================================================================== --- /dev/null 2018-09-14 11:16:31.122530289 +0100 +++ gcc/testsuite/gcc.dg/sizeless-1.c 2018-10-15 14:13:32.996230178 +0100 @@ -0,0 +1,269 @@ +/* { dg-options "-std=gnu99" } */ + +struct initially_struct; +__sizeless_struct initially_struct; /* { dg-error {'initially_struct' defined as wrong kind of tag} } */ + +union initially_union; +__sizeless_struct initially_union; /* { dg-error {'initially_union' defined as wrong kind of tag} } */ + +enum initially_enum { AN_ENUM_VALUE }; +__sizeless_struct initially_enum; /* { dg-error {'initially_enum' defined as wrong kind of tag} } */ + +__sizeless_struct initially_sizeless; +struct initially_sizeless; /* { dg-error {'initially_sizeless' defined as wrong kind of tag} } */ +union initially_sizeless; /* { dg-error {'initially_sizeless' defined as wrong kind of tag} } */ +enum initially_sizeless { ANOTHER_ENUM_VALUE }; /* { dg-error {'initially_sizeless' defined as wrong kind of tag} } */ + +typedef __sizeless_struct { int a; } ta; +typedef __sizeless_struct { int a; } tb; +typedef __sizeless_struct { int a, b; } tc; + +typedef __sizeless_struct ta_wrapper { ta a1, a2; } ta_wrapper; + +__sizeless_struct struct_in_sizeless { + struct { ta a; }; /* { dg-error {field 'a' has sizeless type} } */ + struct { int b; }; +}; +__sizeless_struct union_in_sizeless { + union { ta a; }; /* { dg-error {field 'a' has sizeless type} } */ + union { int b; }; +}; +__sizeless_struct sizeless_in_sizeless { + __sizeless_struct { ta a; }; +}; + +__sizeless_struct flexible_in_sizeless { + int i; + int x[]; /* { dg-error {flexible array member in sizeless struct} } */ +}; + +struct sizeless_in_struct { + __sizeless_struct { ta a; }; /* { dg-error {unnamed field has sizeless type} } */ + __sizeless_struct { int b; }; /* { dg-error {unnamed field has sizeless type} } */ +}; +union sizeless_in_union { + __sizeless_struct { ta a; }; /* { dg-error {unnamed field has sizeless type} } */ + __sizeless_struct { int b; }; /* { dg-error {unnamed field has sizeless type} } */ +}; + +/* Sizeless objects with global scope. */ + +ta global_ta; /* { dg-error {sizeless variable 'global_ta' cannot have static storage duration} } */ +static ta local_ta; /* { dg-error {sizeless variable 'local_ta' cannot have static storage duration} } */ +extern ta extern_ta; /* { dg-error {sizeless variable 'extern_ta' cannot have static storage duration} } */ +__thread ta tls_ta; /* { dg-error {sizeless variable 'tls_ta' cannot have thread-local storage duration} } */ +_Atomic ta atomic_ta; /* { dg-error {sizeless variable 'atomic_ta' cannot have static storage duration} } */ + +/* Sizeless arrays. */ + +typedef ta array_type[2]; /* { dg-error {array type has incomplete element type 'ta'} } */ +extern ta extern_array[]; /* { dg-error {array type has incomplete element type 'ta'} } */ + +/* Sizeless fields. */ + +struct struct1 { + ta a; /* { dg-error {field 'a' has sizeless type} } */ +}; + +union union1 { + ta a; /* { dg-error {field 'a' has sizeless type} } */ +}; + +/* Pointers to sizeless types. */ + +ta *global_ta_ptr; + +/* Sizeless arguments and return values. */ + +void ext_consume_ta (ta); +void ext_consume_varargs (int, ...); +ta ext_produce_ta (); + +/* Main tests for statements and expressions. */ + +void +statements (int n) +{ + /* Local declarations. */ + + ta ta1, ta2; + tb tb1; + tc tc1; + static ta local_static_ta; /* { dg-error {sizeless variable 'local_static_ta' cannot have static storage duration} } */ + extern ta another_extern_ta; /* { dg-error {sizeless variable 'another_extern_ta' cannot have static storage duration} } */ + + /* Layout queries. */ + + sizeof (ta); /* { dg-error {invalid application of 'sizeof' to incomplete type} } */ + sizeof (ta1); /* { dg-error {invalid application of 'sizeof' to incomplete type} } */ + sizeof (ext_produce_ta ()); /* { dg-error {invalid application of 'sizeof' to incomplete type} } */ + _Alignof (ta); /* { dg-error {invalid application of '(_Alignof|__alignof__)' to incomplete type} } */ + _Alignof (ta1); /* { dg-error {invalid application of '(_Alignof|__alignof__)' to incomplete type} } */ + _Alignof (ext_produce_ta ()); /* { dg-error {invalid application of '(_Alignof|__alignof__)' to incomplete type} } */ + + /* Initialization. */ + + ta init_ta1 = ta1; + ta init_ta2 = tb1; /* { dg-error {invalid initializer} } */ + ta init_ta3 = {}; + ta init_ta4 = { 1 }; + ta init_ta5 = { n }; + ta init_ta6 = { n, n }; /* { dg-warning {excess elements in struct initializer} } */ + + int initi_a = ta1; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */ + int initi_b = { ta1 }; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */ + + ta_wrapper init_wrapper1 = {}; + ta_wrapper init_wrapper2 = { ta1 }; + ta_wrapper init_wrapper3 = { ta1, ta1 }; + ta_wrapper init_wrapper4 = { ta1, ta1, ta1 }; /* { dg-warning {excess elements in struct initializer} } */ + + /* Compound literals. */ + + (ta) {}; + (ta) { ta1 }; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */ + (ta) { 1 }; + (ta) { 1, 2 }; /* { dg-warning {excess elements in struct initializer} } */ + (tc) { 1, 2 }; + (tc) { 1, 2, 3 }; /* { dg-warning {excess elements in struct initializer} } */ + + (int) { ta1 }; /* { dg-error {incompatible types when initializing type 'int' using type 'ta'} } */ + + /* Arrays. */ + + ta array[2]; /* { dg-error {array type has incomplete element type 'ta'} } */ + ta zero_length_array[0]; /* { dg-error {array type has incomplete element type 'ta'} } */ + ta empty_init_array[] = {}; /* { dg-error {array type has incomplete element type 'ta'} } */ + /* { dg-error {empty scalar initializer} "" { target *-*-* } .-1 } */ + typedef ta vla_type[n]; /* { dg-error {array type has incomplete element type 'ta'} } */ + + /* Assignment. */ + + n = ta1; /* { dg-error {incompatible types when assigning to type 'int' from type 'ta'} } */ + + ta1 = 0; /* { dg-error {incompatible types when assigning to type 'ta'[^\n]* from type 'int'} } */ + ta1 = ta2; + ta1 = tb1; /* { dg-error {incompatible types when assigning to type 'ta'[^\n]* from type 'tb'} } */ + + /* Casting. */ + + (void) ta1; + (ta) ta1; + (tb) ta1; /* { dg-error {conversion to non-scalar type requested} } */ + + /* Addressing and dereferencing. */ + + ta *ta_ptr = &ta1; + tb *tb_ptr = &ta1; /* { dg-warning {initialization of 'tb \*'[^\n]* from incompatible pointer} } */ + ta1 = *ta_ptr; + ta1 = *tb_ptr; /* { dg-error {incompatible types when assigning to type 'ta'[^\n]* from type 'tb'} } */ + + /* Pointer arithmetic. */ + + ++ta_ptr; /* { dg-error {increment of pointer to an incomplete type 'ta'} } */ + --ta_ptr; /* { dg-error {decrement of pointer to an incomplete type 'ta'} } */ + ta_ptr++; /* { dg-error {increment of pointer to an incomplete type 'ta'} } */ + ta_ptr--; /* { dg-error {decrement of pointer to an incomplete type 'ta'} } */ + ta_ptr += 0; /* { dg-error {invalid use of incomplete typedef 'ta'} } */ + ta_ptr += 1; /* { dg-error {invalid use of incomplete typedef 'ta'} } */ + ta_ptr -= 0; /* { dg-error {invalid use of incomplete typedef 'ta'} } */ + ta_ptr -= 1; /* { dg-error {invalid use of incomplete typedef 'ta'} } */ + ta_ptr - ta_ptr; /* { dg-error {arithmetic on pointer to an incomplete type} } */ + ta1 = ta_ptr[0]; /* { dg-error {invalid use of incomplete typedef 'ta'} } */ + ta1 = ta_ptr[1]; /* { dg-error {invalid use of incomplete typedef 'ta'} } */ + + /* Component accesses. */ + + tc1.a = 1; + tc1.b = 1; + tc1.c = 1; /* { dg-error {'tc'[^\n]* has no member named 'c'} } */ + ta_ptr->a = 1; + ta_ptr->b = 1; /* { dg-error {'ta'[^\n]* has no member named 'b'} } */ + int *int_ptr1 = &tc1.a; + int *int_ptr2 = &tc1.b; + int *int_ptr3 = &ta_ptr->a; + + /* Unary operators. */ + + +ta1; /* { dg-error {wrong type argument to unary plus} } */ + -ta1; /* { dg-error {wrong type argument to unary minus} } */ + ~ta1; /* { dg-error {wrong type argument to bit-complement} } */ + !ta1; /* { dg-error {wrong type argument to unary exclamation mark} } */ + *ta1; /* { dg-error {invalid type argument of unary '\*'} } */ + __real ta1; /* { dg-error {wrong type argument to __real} } */ + __imag ta1; /* { dg-error {wrong type argument to __imag} } */ + ++ta1; /* { dg-error {wrong type argument to increment} } */ + --ta1; /* { dg-error {wrong type argument to decrement} } */ + ta1++; /* { dg-error {wrong type argument to increment} } */ + ta1--; /* { dg-error {wrong type argument to decrement} } */ + + /* Conditional expressions. */ + + ta1 ? 0 : 0; /* { dg-error {used struct type value where scalar is required} } */ + 0 ? ta1 : ta1; + 0 ? ta1 : tb1; /* { dg-error {type mismatch in conditional expression} } */ + 0 ? ta1 : 0; /* { dg-error {type mismatch in conditional expression} } */ + 0 ? 0 : ta1; /* { dg-error {type mismatch in conditional expression} } */ + 0 ?: ta1; /* { dg-error {type mismatch in conditional expression} } */ + + /* Generic associations. */ + + _Generic (ta1, default: 100); + _Generic (1, ta: 10, default: 20); + + /* Function arguments. */ + + ext_consume_ta (ta1); + ext_consume_ta (tb1); /* { dg-error {incompatible type for argument 1 of 'ext_consume_ta'} } */ + ext_consume_varargs (ta1); /* { dg-error {incompatible type for argument 1 of 'ext_consume_varargs'} } */ + ext_consume_varargs (1, ta1); + + /* Function returns. */ + + ext_produce_ta (); + ta1 = ext_produce_ta (); + tb1 = ext_produce_ta (); /* { dg-error {incompatible types when assigning to type 'tb'[^\n]* from type 'ta'} } */ + + /* Varargs processing. */ + + __builtin_va_list valist; + __builtin_va_arg (valist, ta); + + /* Statement expressions. */ + + ({ ta1; }); + ({ ta another_ta = *ta_ptr; another_ta; }); + + /* Use in atomics. */ + + __sync_lock_test_and_set (global_ta_ptr, 0); /* { dg-error {operand type '[^']*'[^\n]* is incompatible with argument 1} } */ +} + +/* Function parameters in definitions. */ + +void +old_style (input_ta) + ta input_ta; +{ + ta ta1 = input_ta; +} + +void +new_style_param (ta input_ta) +{ + ta ta1 = input_ta; +} + +/* Function return values in definitions in definitions. */ + +ta +good_return_ta (ta param) +{ + return param; +} + +ta +bad_return_ta (tb param) +{ + return param; /* { dg-error {incompatible types when returning type 'tb'[^\n]* but 'ta'[^\n]* was expected} } */ +}