From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id 95191385AC3D; Wed, 2 Nov 2022 18:44:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 95191385AC3D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1667414690; bh=+2ZnvQN6PABnyst8z9Qjf5miBowQ9DlA1s6kEGP5018=; h=From:To:Subject:Date:From; b=ERJk+iuHFcA0VmF+ImnZq+KeT5YHkVVCDR/Ij96lyi2X+sn/bFgNPDiiFRwLhUdbz CdA4U4QtYZLqX5X8z1A0kvfhSzK2oMWupSXN9CWGiq39s8OED7pnFC5tR7Ob9GxqBa HSk9Pq7l/J3Buwhnu8n7KbiSzwwzpUI0WrXfTNy4= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Jason Merrill To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/c++-contracts] c++: more tidying X-Act-Checkin: gcc X-Git-Author: Jason Merrill X-Git-Refname: refs/heads/devel/c++-contracts X-Git-Oldrev: 0c073c813d4ca2bbba9d0801171308ff429dbbbe X-Git-Newrev: 43334477200de54ea246f714a55594c12b8a4d06 Message-Id: <20221102184450.95191385AC3D@sourceware.org> Date: Wed, 2 Nov 2022 18:44:50 +0000 (GMT) List-Id: https://gcc.gnu.org/g:43334477200de54ea246f714a55594c12b8a4d06 commit 43334477200de54ea246f714a55594c12b8a4d06 Author: Jason Merrill Date: Tue Nov 1 09:45:00 2022 -0400 c++: more tidying Move more macros to contracts.h, remove unnecessary extern decls, tweak comments, remove DECL_ORIGINAL_FN. Diff: --- gcc/cp/contracts.h | 120 ++++++++++++++++++++++++++++++++++++---------------- gcc/cp/cp-tree.h | 105 +++++++++------------------------------------ gcc/cp/parser.h | 2 +- gcc/cp/constexpr.cc | 4 +- gcc/cp/contracts.cc | 41 +++++------------- gcc/cp/decl.cc | 5 +-- gcc/cp/module.cc | 2 +- 7 files changed, 120 insertions(+), 159 deletions(-) diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h index ec48a04da36..ad382cf187b 100644 --- a/gcc/cp/contracts.h +++ b/gcc/cp/contracts.h @@ -170,6 +170,28 @@ enum contract_matching_context cmc_override }; +/* True if NODE is any kind of contract. */ +#define CONTRACT_P(NODE) \ + (TREE_CODE (NODE) == ASSERTION_STMT \ + || TREE_CODE (NODE) == PRECONDITION_STMT \ + || TREE_CODE (NODE) == POSTCONDITION_STMT) + +/* True if NODE is a contract condition. */ +#define CONTRACT_CONDITION_P(NODE) \ + (TREE_CODE (NODE) == PRECONDITION_STMT \ + || TREE_CODE (NODE) == POSTCONDITION_STMT) + +/* True if NODE is a precondition. */ +#define PRECONDITION_P(NODE) \ + (TREE_CODE (NODE) == PRECONDITION_STMT) + +/* True if NODE is a postcondition. */ +#define POSTCONDITION_P(NODE) \ + (TREE_CODE (NODE) == POSTCONDITION_STMT) + +#define CONTRACT_CHECK(NODE) \ + (TREE_CHECK3 (NODE, ASSERTION_STMT, PRECONDITION_STMT, POSTCONDITION_STMT)) + /* True iff the FUNCTION_DECL NODE currently has any contracts. */ #define DECL_HAS_CONTRACTS_P(NODE) \ (DECL_CONTRACTS (NODE) != NULL_TREE) @@ -195,6 +217,48 @@ enum contract_matching_context #define CONTRACT_STATEMENT(NODE) \ (TREE_VALUE (TREE_VALUE (NODE))) +/* True if the contract semantic was specified literally. If true, the + contract mode is an identifier containing the semantic. Otherwise, + it is a TREE_LIST whose TREE_VALUE is the level and whose TREE_PURPOSE + is the role. */ +#define CONTRACT_LITERAL_MODE_P(NODE) \ + (CONTRACT_MODE (NODE) != NULL_TREE \ + && TREE_CODE (CONTRACT_MODE (NODE)) == IDENTIFIER_NODE) + +/* The identifier denoting the literal semantic of the contract. */ +#define CONTRACT_LITERAL_SEMANTIC(NODE) \ + (TREE_OPERAND (NODE, 0)) + +/* The written "mode" of the contract. Either an IDENTIFIER with the + literal semantic or a TREE_LIST containing the level and role. */ +#define CONTRACT_MODE(NODE) \ + (TREE_OPERAND (CONTRACT_CHECK (NODE), 0)) + +/* The identifier denoting the build level of the contract. */ +#define CONTRACT_LEVEL(NODE) \ + (TREE_VALUE (CONTRACT_MODE (NODE))) + +/* The identifier denoting the role of the contract */ +#define CONTRACT_ROLE(NODE) \ + (TREE_PURPOSE (CONTRACT_MODE (NODE))) + +/* The parsed condition of the contract. */ +#define CONTRACT_CONDITION(NODE) \ + (TREE_OPERAND (CONTRACT_CHECK (NODE), 1)) + +/* True iff the condition of the contract NODE is not yet parsed. */ +#define CONTRACT_CONDITION_DEFERRED_P(NODE) \ + (TREE_CODE (CONTRACT_CONDITION (NODE)) == DEFERRED_PARSE) + +/* The raw comment of the contract. */ +#define CONTRACT_COMMENT(NODE) \ + (TREE_OPERAND (CONTRACT_CHECK (NODE), 2)) + +/* The VAR_DECL of a postcondition result. For deferred contracts, this + is an IDENTIFIER. */ +#define POSTCONDITION_IDENTIFIER(NODE) \ + (TREE_OPERAND (POSTCONDITION_STMT_CHECK (NODE), 3)) + /* For a FUNCTION_DECL of a guarded function, this holds the function decl where pre contract checks are emitted. */ #define DECL_PRE_FN(NODE) \ @@ -205,54 +269,38 @@ enum contract_matching_context #define DECL_POST_FN(NODE) \ (get_postcondition_function ((NODE))) -/* For a FUNCTION_DECL of a pre/post function, this points back to the - original guarded function. */ -#define DECL_ORIGINAL_FN(NODE) \ - (DECL_ABSTRACT_ORIGIN (NODE)) - /* True iff the FUNCTION_DECL is the pre function for a guarded function. */ #define DECL_IS_PRE_FN_P(NODE) \ - (DECL_ORIGINAL_FN (NODE) && DECL_PRE_FN (DECL_ORIGINAL_FN (NODE)) == NODE) + (DECL_ABSTRACT_ORIGIN (NODE) && DECL_PRE_FN (DECL_ABSTRACT_ORIGIN (NODE)) == NODE) /* True iff the FUNCTION_DECL is the post function for a guarded function. */ #define DECL_IS_POST_FN_P(NODE) \ - (DECL_ORIGINAL_FN (NODE) && DECL_POST_FN (DECL_ORIGINAL_FN (NODE)) == NODE) + (DECL_ABSTRACT_ORIGIN (NODE) && DECL_POST_FN (DECL_ABSTRACT_ORIGIN (NODE)) == NODE) -extern tree invalidate_contract (tree); -extern tree finish_contract_attribute (tree, tree); -extern void update_late_contract (tree, tree, tree); extern void remove_contract_attributes (tree); extern void copy_contract_attributes (tree, tree); -extern tree splice_out_contracts (tree); -extern bool check_postcondition_result (tree, tree, location_t); -extern void rebuild_postconditions (tree); -extern bool match_contract_conditions (location_t, tree, location_t, tree, contract_matching_context); -extern void defer_guarded_contract_match (tree, tree, tree); -extern void match_deferred_contracts (tree); -extern void remap_contract (tree, tree, tree, bool); extern void remap_contracts (tree, tree, tree, bool); -extern void remap_dummy_this (tree, tree *); -extern bool contract_active_p (tree); -extern bool contract_any_active_p (tree); -extern bool contract_any_deferred_p (tree); -extern bool all_attributes_are_contracts_p (tree); -extern void build_contract_function_decls (tree); -extern void set_contract_functions (tree, tree, tree); -extern tree start_postcondition_statement (); -extern void finish_postcondition_statement (tree); -extern tree build_contract_check (tree); -extern tree get_postcondition_result_parameter (tree); +extern void maybe_update_postconditions (tree); +extern void rebuild_postconditions (tree); +extern bool check_postcondition_result (tree, tree, location_t); extern tree get_precondition_function (tree); extern tree get_postcondition_function (tree); -extern tree get_contracts_original_fn (tree); -extern void emit_assertion (tree); -extern void emit_preconditions (tree); -extern void emit_postconditions_cleanup (tree); -extern void maybe_update_postconditions (tree); +extern void duplicate_contracts (tree, tree); +extern bool match_contract_conditions (location_t, tree, location_t, tree, contract_matching_context); +extern void match_deferred_contracts (tree); +extern void defer_guarded_contract_match (tree, tree, tree); +extern bool diagnose_misapplied_contracts (tree); +extern tree finish_contract_attribute (tree, tree); +extern tree invalidate_contract (tree); +extern void update_late_contract (tree, tree, tree); +extern tree splice_out_contracts (tree); +extern bool all_attributes_are_contracts_p (tree); +extern void inherit_base_contracts (tree, tree); +extern tree apply_postcondition_to_return (tree); extern void start_function_contracts (tree); extern void finish_function_contracts (tree); -extern tree apply_postcondition_to_return (tree); -extern void duplicate_contracts (tree, tree); -extern void inherit_base_contracts (tree, tree); +extern void set_contract_functions (tree, tree, tree); +extern tree build_contract_check (tree); +extern void emit_assertion (tree); #endif /* ! GCC_CP_CONTRACT_H */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f4104c8751d..c9f176759eb 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1380,90 +1380,6 @@ struct GTY (()) tree_static_assert { location_t location; }; -/* True if NODE is any kind of contract. */ -#define CONTRACT_P(NODE) \ - (TREE_CODE (NODE) == ASSERTION_STMT \ - || TREE_CODE (NODE) == PRECONDITION_STMT \ - || TREE_CODE (NODE) == POSTCONDITION_STMT) - -/* True if NODE is a contract condition. */ -#define CONTRACT_CONDITION_P(NODE) \ - (TREE_CODE (NODE) == PRECONDITION_STMT \ - || TREE_CODE (NODE) == POSTCONDITION_STMT) - -/* True if NODE is a precondition. */ -#define PRECONDITION_P(NODE) \ - (TREE_CODE (NODE) == PRECONDITION_STMT) - -/* True if NODE is a postcondition. */ -#define POSTCONDITION_P(NODE) \ - (TREE_CODE (NODE) == POSTCONDITION_STMT) - -#define CONTRACT_CHECK(NODE) \ - (TREE_CHECK3 (NODE, ASSERTION_STMT, PRECONDITION_STMT, POSTCONDITION_STMT)) - -/* Returns the computed semantic of the node. */ - -inline contract_semantic -get_contract_semantic (const_tree t) -{ - return (contract_semantic) (TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) - | (TREE_LANG_FLAG_2 (t) << 1) - | (TREE_LANG_FLAG_0 ((t)) << 2)); -} - -/* Sets the computed semantic of the node. */ - -inline void -set_contract_semantic (tree t, contract_semantic semantic) -{ - TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) = semantic & 0x01; - TREE_LANG_FLAG_2 (t) = (semantic & 0x02) >> 1; - TREE_LANG_FLAG_0 (t) = (semantic & 0x04) >> 2; -} - -/* True if the contract semantic was specified literally. If true, the - contract mode is an identifier containing the semantic. Otherwise, - it is a TREE_LIST whose TREE_VALUE is the level and whose TREE_PURPOSE - is the role. */ -#define CONTRACT_LITERAL_MODE_P(NODE) \ - (CONTRACT_MODE (NODE) != NULL_TREE \ - && TREE_CODE (CONTRACT_MODE (NODE)) == IDENTIFIER_NODE) - -/* The identifier denoting the literal semantic of the contract. */ -#define CONTRACT_LITERAL_SEMANTIC(NODE) \ - (TREE_OPERAND (NODE, 0)) - -/* The written "mode" of the contract. Either an IDENTIFIER with the - literal semantic or a TREE_LIST containing the level and role. */ -#define CONTRACT_MODE(NODE) \ - (TREE_OPERAND (CONTRACT_CHECK (NODE), 0)) - -/* The identifier denoting the build level of the contract. */ -#define CONTRACT_LEVEL(NODE) \ - (TREE_VALUE (CONTRACT_MODE (NODE))) - -/* The identifier denoting the role of the contract */ -#define CONTRACT_ROLE(NODE) \ - (TREE_PURPOSE (CONTRACT_MODE (NODE))) - -/* The parsed condition of the contract. */ -#define CONTRACT_CONDITION(NODE) \ - (TREE_OPERAND (CONTRACT_CHECK (NODE), 1)) - -/* True iff the condition of the contract NODE is not yet parsed. */ -#define CONTRACT_CONDITION_DEFERRED_P(NODE) \ - (TREE_CODE (CONTRACT_CONDITION (NODE)) == DEFERRED_PARSE) - -/* The raw comment of the contract. */ -#define CONTRACT_COMMENT(NODE) \ - (TREE_OPERAND (CONTRACT_CHECK (NODE), 2)) - -/* The VAR_DECL of a postcondition result. For deferred contracts, this - is an IDENTIFIER. */ -#define POSTCONDITION_IDENTIFIER(NODE) \ - (TREE_OPERAND (POSTCONDITION_STMT_CHECK (NODE), 3)) - struct GTY (()) tree_argument_pack_select { struct tree_common common; tree argument_pack; @@ -6941,7 +6857,6 @@ extern tree push_library_fn (tree, tree, tree, int); extern tree push_throw_library_fn (tree, tree); extern void warn_misplaced_attr_for_class_type (location_t location, tree class_type); -extern bool diagnose_misapplied_contracts (tree); extern tree check_tag_decl (cp_decl_specifier_seq *, bool); extern tree shadow_tag (cp_decl_specifier_seq *); extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *, bool); @@ -8649,6 +8564,26 @@ set_decl_contracts (tree decl, tree contract_attrs) DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), contract_attrs); } +/* Returns the computed semantic of the node. */ + +inline contract_semantic +get_contract_semantic (const_tree t) +{ + return (contract_semantic) (TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) + | (TREE_LANG_FLAG_2 (t) << 1) + | (TREE_LANG_FLAG_0 ((t)) << 2)); +} + +/* Sets the computed semantic of the node. */ + +inline void +set_contract_semantic (tree t, contract_semantic semantic) +{ + TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) = semantic & 0x01; + TREE_LANG_FLAG_2 (t) = (semantic & 0x02) >> 1; + TREE_LANG_FLAG_0 (t) = (semantic & 0x04) >> 2; +} + /* Inline bodies. */ inline tree diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 1b6c359a4c0..f695f4566b4 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -318,7 +318,7 @@ struct GTY(()) cp_parser { /* TRUE if the decl-specifier-seq preceding a declarator includes the 'friend' specifier. This prevents attributes on friend function declarations from being parsed in the complete class context. */ - /* ??? Maybe use defer_guarded_contract_match instead? */ + /* ??? But they should be; maybe use defer_guarded_contract_match? */ bool declaring_friend_p; /* TRUE if we are presently parsing a template-argument-list. */ diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index b3041d9c3d3..8a858be99f7 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -9868,9 +9868,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case POSTCONDITION_STMT: if (!checked_contract_p (get_contract_semantic (t))) return true; - if (!RECUR (CONTRACT_CONDITION (t), rval)) - return false; - return true; + return RECUR (CONTRACT_CONDITION (t), rval); case LABEL_EXPR: t = LABEL_EXPR_LABEL (t); diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index dc0df471dfc..6db3b750fda 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -138,14 +138,14 @@ along with GCC; see the file COPYING3. If not see For cdtors a post contract is implemented using a CLEANUP_STMT. - FIXME the compiler already handles sharing cleanup code on multiple exit - paths properly, so this outlining seems unnecessary if we represent the - postcondition as a cleanup for all functions. + FIXME the compiler already shores cleanup code on multiple exit paths, so + this outlining seems unnecessary if we represent the postcondition as a + cleanup for all functions. More helpful for optimization might be to make the contracts a wrapper function (for non-variadic functions), that could be inlined into a caller while preserving the call to the actual function? Either that or - turn a never-continue post contract into an assume in the caller. */ + mirror a never-continue post contract with an assume in the caller. */ #include "config.h" #include "system.h" @@ -942,7 +942,7 @@ void copy_contract_attributes (tree olddecl, tree newdecl) /* Returns the parameter corresponding to the return value of a guarded function D. Returns NULL_TREE if D has no postconditions or is void. */ -tree +static tree get_postcondition_result_parameter (tree d) { if (!d || d == error_mark_node) @@ -994,7 +994,7 @@ retain_decl (tree decl, copy_body_data *) This is also used to reuse a parent type's contracts on virtual methods. */ -void +static void remap_contract (tree src, tree dst, tree contract, bool duplicate_p) { copy_body_data id; @@ -1101,7 +1101,7 @@ remap_dummy_this_1 (tree *tp, int *, void *data) /* Replace all references to dummy this parameters in EXPR with references to the first argument of the FUNCTION_DECL FN. */ -void +static void remap_dummy_this (tree fn, tree *expr) { walk_tree (expr, remap_dummy_this_1, fn, NULL); @@ -1536,7 +1536,7 @@ handle_contracts_p (tree decl1) { return (flag_contracts && !processing_template_decl - && DECL_ORIGINAL_FN (decl1) == NULL_TREE + && DECL_ABSTRACT_ORIGIN (decl1) == NULL_TREE && contract_any_active_p (DECL_CONTRACTS (decl1))); } @@ -1579,7 +1579,7 @@ build_postcondition_function (tree d) return build_contract_condition_function (d, /*pre=*/false); } -void +static void build_contract_function_decls (tree d) { /* Constructors and destructors have their contracts inserted inline. */ @@ -1592,25 +1592,6 @@ build_contract_function_decls (tree d) set_contract_functions (d, pre, post); } -/* Begin a new scope for the postcondition. */ - -tree -start_postcondition_statement () -{ - tree list = push_stmt_list (); - tree stmt = begin_compound_stmt (BCS_NORMAL); - return build_tree_list (list, stmt); -} - -/* Finish the block containing the postcondition check. */ - -void -finish_postcondition_statement (tree stmt) -{ - finish_compound_stmt (TREE_VALUE (stmt)); - pop_stmt_list (TREE_PURPOSE (stmt)); -} - static const char * get_contract_level_name (tree contract) { @@ -1887,7 +1868,7 @@ emit_assertion (tree attr) /* Emit statements for precondition attributes. */ -void +static void emit_preconditions (tree attr) { return emit_contract_conditions (attr, PRECONDITION_STMT); @@ -1895,7 +1876,7 @@ emit_preconditions (tree attr) /* Emit statements for postcondition attributes. */ -void +static void emit_postconditions_cleanup (tree contracts) { tree stmts = push_stmt_list (); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index c845c3d7e8c..9e591d592cf 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -13256,14 +13256,14 @@ grokdeclarator (const cp_declarator *declarator, returned_attrs = attr_chainon (returned_attrs, att); } - /* Contract attributes appertain to the declaration. */ + /* Actually apply the contract attributes to the declaration. */ for (tree *p = &attrs; *p;) { tree l = *p; if (cxx_contract_attribute_p (l)) { *p = TREE_CHAIN (l); - /* Intentially reverse order of contracts so they're + /* Intentionally reverse order of contracts so they're reversed back into their lexical order. */ TREE_CHAIN (l) = NULL_TREE; returned_attrs = chainon (l, returned_attrs); @@ -18244,7 +18244,6 @@ finish_function (bool inline_p) return fndecl; } - /* Create the FUNCTION_DECL for a function definition. DECLSPECS and DECLARATOR are the parts of the declaration; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 90f945a615b..fdf85c365db 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -10825,7 +10825,7 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key) && (!DECL_IS_UNDECLARED_BUILTIN (m_inner) || !DECL_EXTERN_C_P (m_inner) || DECL_EXTERN_C_P (d_inner)) - /* Reject if one is they're different member of a + /* Reject if one is a different member of a guarded/pre/post fn set. */ && (!flag_contracts || (DECL_IS_PRE_FN_P (d_inner)