diff options
author | Jeff Chapman II <jchapman@lock3software.com> | 2021-06-29 16:52:56 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-11-18 21:41:14 -0500 |
commit | 2efb237ffc68ec9bb17982434f5941bfa14f8b50 (patch) | |
tree | 1c4cc161c09a6cb9a87cd38f752ac9846e86fc54 /gcc/cp/contracts.h | |
parent | ea63396f6b08f88f1cde827e6cab94cd488f7fa7 (diff) | |
download | gcc-2efb237ffc68ec9bb17982434f5941bfa14f8b50.zip gcc-2efb237ffc68ec9bb17982434f5941bfa14f8b50.tar.gz gcc-2efb237ffc68ec9bb17982434f5941bfa14f8b50.tar.bz2 |
c++: implement P1492 contracts
Implement the P1492 versions of contracts, along with extensions that
support the emulation of N4820 and other proposals. This implementation
assigns a concrete semantic (one of: ignore, assume, enforce, or
observe) to each contract attribute depending on its labels and
configuration options.
Co-authored-by: Andrew Sutton <asutton@lock3software.com>
Co-authored-by: Andrew Marmaduke <amarmaduke@lock3software.com>
Co-authored-by: Michael Lopez <mlopez@lock3software.com>
Co-authored-by: Jason Merrill <jason@redhat.com>
gcc/ChangeLog:
* doc/invoke.texi: Document contracts flags.
gcc/c-family/ChangeLog:
* c.opt: Add contracts flags.
* c-cppbuiltin.cc (c_cpp_builtins): Add contracts feature-test
macros.
gcc/cp/ChangeLog:
* cp-tree.h (enum cp_tree_index): Add
CPTI_PSEUDO_CONTRACT_VIOLATION.
(pseudo_contract_violation_type): New macro.
(struct saved_scope): Add x_processing_contract_condition.
(processing_contract_condition): New macro.
(comparing_override_contracts): New variable decl.
(find_contract): New inline.
(set_decl_contracts): New inline.
(get_contract_semantic): New inline.
(set_contract_semantic): New inline.
* constexpr.cc (cxx_eval_assert): Split out from...
(cxx_eval_internal_function): ...here.
(cxx_eval_constant_expression): Use it for contracts.
(potential_constant_expression_1): Handle contracts.
* cp-gimplify.cc (cp_genericize_r): Handle contracts.
* cp-objcp-common.cc (cp_tree_size): Handle contracts.
(cp_common_init_ts): Handle contracts.
(cp_handle_option): Handle contracts.
* decl.cc (duplicate_decls): Handle contracts.
(check_tag_decl): Check for bogus contracts.
(start_decl): Check flag_contracts.
(grokfndecl): Call rebuild_postconditions.
(grokdeclarator): Handle contract attributes.
(start_preparsed_function): Call start_function_contracts.
(finish_function): Call finish_function_contracts.
* decl2.cc (cp_check_const_attributes): Skip contracts.
(comdat_linkage): Handle outlined contracts.
* error.cc (dump_type): Handle null TYPE_IDENTIFIER.
* g++spec.cc (EXPERIMENTAL): New macro.
(lang_specific_driver): Add -lstdc++exp if -fcontracts.
* mangle.cc (write_encoding): Handle outlined contracts.
* module.cc (trees_out::fn_parms_init): Handle outlined contracts.
(trees_in::fn_parms_init): Likewise.
(check_mergeable_decl): Likewise.
(module_state_config::get_dialect): Record -fcontracts.
* parser.h (struct cp_unparsed_functions_entry): Add contracts.
* parser.cc (unparsed_contracts): New macro.
(push_unparsed_function_queues): Adjust.
(contract_attribute_p): New.
(cp_parser_statement): Check contracts.
(cp_parser_decl_specifier_seq): Handle contracts.
(cp_parser_skip_to_closing_square_bracket): Split out...
(cp_parser_skip_up_to_closing_square_bracket): ...this fn.
(cp_parser_class_specifier): Do contract late parsing.
(cp_parser_class_head): Check contracts.
(cp_parser_contract_role): New.
(cp_parser_contract_mode_opt): New.
(find_error, contains_error_p): New.
(cp_parser_contract_attribute_spec): New.
(cp_parser_late_contract_condition): New.
(cp_parser_std_attribute_spec): Handle contracts.
(cp_parser_save_default_args): Also save contracts.
* pt.cc (register_parameter_specializations): No longer static.
(register_local_identity): New.
(check_explicit_specialization): Call remove_contract_attributes.
(tsubst_contract, tsubst_contract_attribute): New.
(tsubst_contract_attributes): New.
(tsubst_attribute): Add comment.
(tsubst_copy): Also allow parm when processing_contract_condition.
(tsubst_expr): Handle contracts.
(regenerate_decl_from_template): Handle contracts.
* search.cc (check_final_overrider): Compare contracts.
* semantics.cc (set_cleanup_locs): Skip POSTCONDITION_STMT.
(finish_non_static_data_member): Check contracts.
(finish_this_expr): Check contracts.
(process_outer_var_ref): Handle contracts.
(finish_id_expression_1): Handle contracts.
(apply_deduced_return_type): Adjust contracts.
* tree.cc (handle_contract_attribute): New.
(get_innermost_component, is_this_expression): New.
(comparing_this_references): New.
(equivalent_member_references): New.
(cp_tree_equal): Check it.
* typeck.cc (check_return_expr): Apply contracts.
* Make-lang.in: Add contracts.o.
* config-lang.in: Add contracts.cc.
* cp-tree.def (ASSERTION_STMT, PRECONDITION_STMT)
(POSTCONDITION_STMT): New.
* contracts.h: New file.
* contracts.cc: New file.
gcc/testsuite/ChangeLog:
* g++.dg/modules/modules.exp: Pass dg-options to link command.
* lib/g++.exp: Add -L for libstdc++exp.a.
* g++.dg/contracts/backtrace_handler/assert_fail.cpp: New test.
* g++.dg/contracts/backtrace_handler/handle_contract_violation.cpp: New test.
* g++.dg/contracts/contracts-access1.C: New test.
* g++.dg/contracts/contracts-assume1.C: New test.
* g++.dg/contracts/contracts-assume2.C: New test.
* g++.dg/contracts/contracts-assume3.C: New test.
* g++.dg/contracts/contracts-assume4.C: New test.
* g++.dg/contracts/contracts-assume5.C: New test.
* g++.dg/contracts/contracts-assume6.C: New test.
* g++.dg/contracts/contracts-comdat1.C: New test.
* g++.dg/contracts/contracts-config1.C: New test.
* g++.dg/contracts/contracts-constexpr1.C: New test.
* g++.dg/contracts/contracts-constexpr2.C: New test.
* g++.dg/contracts/contracts-constexpr3.C: New test.
* g++.dg/contracts/contracts-conversion1.C: New test.
* g++.dg/contracts/contracts-ctor-dtor1.C: New test.
* g++.dg/contracts/contracts-ctor-dtor2.C: New test.
* g++.dg/contracts/contracts-cv1.C: New test.
* g++.dg/contracts/contracts-deduced1.C: New test.
* g++.dg/contracts/contracts-deduced2.C: New test.
* g++.dg/contracts/contracts-friend1.C: New test.
* g++.dg/contracts/contracts-ft1.C: New test.
* g++.dg/contracts/contracts-ignore1.C: New test.
* g++.dg/contracts/contracts-ignore2.C: New test.
* g++.dg/contracts/contracts-large-return.C: New test.
* g++.dg/contracts/contracts-multiline1.C: New test.
* g++.dg/contracts/contracts-multiple-inheritance1.C: New test.
* g++.dg/contracts/contracts-multiple-inheritance2.C: New test.
* g++.dg/contracts/contracts-nested-class1.C: New test.
* g++.dg/contracts/contracts-nested-class2.C: New test.
* g++.dg/contracts/contracts-nocopy1.C: New test.
* g++.dg/contracts/contracts-override.C: New test.
* g++.dg/contracts/contracts-post1.C: New test.
* g++.dg/contracts/contracts-post2.C: New test.
* g++.dg/contracts/contracts-post3.C: New test.
* g++.dg/contracts/contracts-post4.C: New test.
* g++.dg/contracts/contracts-post5.C: New test.
* g++.dg/contracts/contracts-post6.C: New test.
* g++.dg/contracts/contracts-pre1.C: New test.
* g++.dg/contracts/contracts-pre10.C: New test.
* g++.dg/contracts/contracts-pre2.C: New test.
* g++.dg/contracts/contracts-pre2a1.C: New test.
* g++.dg/contracts/contracts-pre2a2.C: New test.
* g++.dg/contracts/contracts-pre3.C: New test.
* g++.dg/contracts/contracts-pre4.C: New test.
* g++.dg/contracts/contracts-pre5.C: New test.
* g++.dg/contracts/contracts-pre6.C: New test.
* g++.dg/contracts/contracts-pre7.C: New test.
* g++.dg/contracts/contracts-pre9.C: New test.
* g++.dg/contracts/contracts-redecl1.C: New test.
* g++.dg/contracts/contracts-redecl2.C: New test.
* g++.dg/contracts/contracts-redecl3.C: New test.
* g++.dg/contracts/contracts-redecl4.C: New test.
* g++.dg/contracts/contracts-redecl5.C: New test.
* g++.dg/contracts/contracts-redecl6.C: New test.
* g++.dg/contracts/contracts-redecl7.C: New test.
* g++.dg/contracts/contracts-redecl8.C: New test.
* g++.dg/contracts/contracts-tmpl-attr1.C: New test.
* g++.dg/contracts/contracts-tmpl-spec1.C: New test.
* g++.dg/contracts/contracts-tmpl-spec2.C: New test.
* g++.dg/contracts/contracts-tmpl-spec3.C: New test.
* g++.dg/contracts/contracts1.C: New test.
* g++.dg/contracts/contracts10.C: New test.
* g++.dg/contracts/contracts11.C: New test.
* g++.dg/contracts/contracts12.C: New test.
* g++.dg/contracts/contracts13.C: New test.
* g++.dg/contracts/contracts14.C: New test.
* g++.dg/contracts/contracts15.C: New test.
* g++.dg/contracts/contracts16.C: New test.
* g++.dg/contracts/contracts17.C: New test.
* g++.dg/contracts/contracts18.C: New test.
* g++.dg/contracts/contracts19.C: New test.
* g++.dg/contracts/contracts2.C: New test.
* g++.dg/contracts/contracts20.C: New test.
* g++.dg/contracts/contracts22.C: New test.
* g++.dg/contracts/contracts24.C: New test.
* g++.dg/contracts/contracts25.C: New test.
* g++.dg/contracts/contracts3.C: New test.
* g++.dg/contracts/contracts35.C: New test.
* g++.dg/contracts/contracts4.C: New test.
* g++.dg/contracts/contracts5.C: New test.
* g++.dg/contracts/contracts6.C: New test.
* g++.dg/contracts/contracts7.C: New test.
* g++.dg/contracts/contracts8.C: New test.
* g++.dg/contracts/contracts9.C: New test.
* g++.dg/modules/contracts-1_a.C: New test.
* g++.dg/modules/contracts-1_b.C: New test.
* g++.dg/modules/contracts-2_a.C: New test.
* g++.dg/modules/contracts-2_b.C: New test.
* g++.dg/modules/contracts-2_c.C: New test.
* g++.dg/modules/contracts-3_a.C: New test.
* g++.dg/modules/contracts-3_b.C: New test.
* g++.dg/modules/contracts-4_a.C: New test.
* g++.dg/modules/contracts-4_b.C: New test.
* g++.dg/modules/contracts-4_c.C: New test.
* g++.dg/modules/contracts-4_d.C: New test.
* g++.dg/modules/contracts-tpl-friend-1_a.C: New test.
* g++.dg/modules/contracts-tpl-friend-1_b.C: New test.
* g++.dg/contracts/backtrace_handler/Makefile: New test.
* g++.dg/contracts/backtrace_handler/README: New test.
* g++.dg/contracts/backtrace_handler/example_out.txt: New test.
* g++.dg/contracts/backtrace_handler/example_pretty.txt: New test.
* g++.dg/contracts/backtrace_handler/prettytrace.sh: New test.
* g++.dg/contracts/except_preload_handler/Makefile: New test.
* g++.dg/contracts/except_preload_handler/README: New test.
* g++.dg/contracts/except_preload_handler/assert_fail.cpp: New test.
* g++.dg/contracts/except_preload_handler/handle_contract_violation.cpp: New test.
* g++.dg/contracts/noexcept_preload_handler/Makefile: New test.
* g++.dg/contracts/noexcept_preload_handler/README: New test.
* g++.dg/contracts/noexcept_preload_handler/assert_fail.cpp: New test.
* g++.dg/contracts/noexcept_preload_handler/handle_contract_violation.cpp: New test.
* g++.dg/contracts/preload_handler/Makefile: New test.
* g++.dg/contracts/preload_handler/README: New test.
* g++.dg/contracts/preload_handler/assert_fail.cpp: New test.
* g++.dg/contracts/preload_handler/handle_contract_violation.cpp: New test.
* g++.dg/contracts/preload_nocontinue_handler/Makefile: New test.
* g++.dg/contracts/preload_nocontinue_handler/README: New test.
* g++.dg/contracts/preload_nocontinue_handler/assert_fail.cpp: New test.
* g++.dg/contracts/preload_nocontinue_handler/handle_contract_violation.cpp: New test.
* g++.dg/contracts/preload_nocontinue_handler/nocontinue.cpp: New test.
Diffstat (limited to 'gcc/cp/contracts.h')
-rw-r--r-- | gcc/cp/contracts.h | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h new file mode 100644 index 0000000..4050a38 --- /dev/null +++ b/gcc/cp/contracts.h @@ -0,0 +1,305 @@ +/* Definitions for C++ contract levels. Implements functionality described in + the N4820 working draft version of contracts, P1290, P1332, and P1429. + Copyright (C) 2020-2022 Free Software Foundation, Inc. + Contributed by Jeff Chapman II (jchapman@lock3software.com) + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_CP_CONTRACT_H +#define GCC_CP_CONTRACT_H + +/* Contract levels approximate the complexity of the expression. */ + +enum contract_level +{ + CONTRACT_INVALID, + CONTRACT_DEFAULT, + CONTRACT_AUDIT, + CONTRACT_AXIOM +}; + +/* The concrete semantics determine the behavior of a contract. */ + +enum contract_semantic +{ + CCS_INVALID, + CCS_IGNORE, + CCS_ASSUME, + CCS_NEVER, + CCS_MAYBE +}; + +/* True if the contract is unchecked. */ + +inline bool +unchecked_contract_p (contract_semantic cs) +{ + return cs == CCS_IGNORE || cs == CCS_ASSUME; +} + +/* True if the contract is checked. */ + +inline bool +checked_contract_p (contract_semantic cs) +{ + return cs >= CCS_NEVER; +} + +/* Must match std::contract_violation_continuation_mode in <contract>. */ +enum contract_continuation +{ + NEVER_CONTINUE, + MAYBE_CONTINUE +}; + +/* Assertion role info. */ +struct contract_role +{ + const char *name; + contract_semantic default_semantic; + contract_semantic audit_semantic; + contract_semantic axiom_semantic; +}; + +/* Information for configured contract semantics. */ + +struct contract_configuration +{ + contract_level level; + contract_role* role; +}; + +/* A contract mode contains information used to derive the checking + and assumption semantics of a contract. This is either a dynamic + configuration, meaning it derives from the build mode, or it is + explicitly specified. */ + +struct contract_mode +{ + contract_mode () : kind(cm_invalid) {} + contract_mode (contract_level level, contract_role *role = NULL) + : kind(cm_dynamic) + { + contract_configuration cc; + cc.level = level; + cc.role = role; + u.config = cc; + } + contract_mode (contract_semantic semantic) : kind(cm_explicit) + { + u.semantic = semantic; + } + + contract_level get_level () const + { + gcc_assert (kind == cm_dynamic); + return u.config.level; + } + + contract_role *get_role () const + { + gcc_assert (kind == cm_dynamic); + return u.config.role; + } + + contract_semantic get_semantic () const + { + gcc_assert (kind == cm_explicit); + return u.semantic; + } + + enum { cm_invalid, cm_dynamic, cm_explicit } kind; + + union + { + contract_configuration config; + contract_semantic semantic; + } u; +}; + +extern contract_role *get_contract_role (const char *); +extern contract_role *add_contract_role (const char *, + contract_semantic, + contract_semantic, + contract_semantic, + bool = true); +extern void validate_contract_role (contract_role *); +extern void setup_default_contract_role (bool = true); +extern contract_semantic lookup_concrete_semantic (const char *); + +/* Map a source level semantic or level name to its value, or invalid. */ +extern contract_semantic map_contract_semantic (const char *); +extern contract_level map_contract_level (const char *); + +/* Check if an attribute is a cxx contract attribute. */ +extern bool cxx_contract_attribute_p (const_tree); +extern bool cp_contract_assertion_p (const_tree); + +/* Returns the default role. */ + +inline contract_role * +get_default_contract_role () +{ + return get_contract_role ("default"); +} + +/* Handle various command line arguments related to semantic mapping. */ +extern void handle_OPT_fcontract_build_level_ (const char *); +extern void handle_OPT_fcontract_assumption_mode_ (const char *); +extern void handle_OPT_fcontract_continuation_mode_ (const char *); +extern void handle_OPT_fcontract_role_ (const char *); +extern void handle_OPT_fcontract_semantic_ (const char *); + +enum contract_matching_context +{ + cmc_declaration, + 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) + +/* For a FUNCTION_DECL of a guarded function, this points to a list of the pre + and post contracts of the first decl of NODE in original order. */ +#define DECL_CONTRACTS(NODE) \ + (find_contract (DECL_ATTRIBUTES (NODE))) + +/* The next contract (if any) after this one in an attribute list. */ +#define CONTRACT_CHAIN(NODE) \ + (find_contract (TREE_CHAIN (NODE))) + +/* The wrapper of the original source location of a list of contracts. */ +#define CONTRACT_SOURCE_LOCATION_WRAPPER(NODE) \ + (TREE_PURPOSE (TREE_VALUE (NODE))) + +/* The original source location of a list of contracts. */ +#define CONTRACT_SOURCE_LOCATION(NODE) \ + (EXPR_LOCATION (CONTRACT_SOURCE_LOCATION_WRAPPER (NODE))) + +/* The actual code _STMT for a contract attribute. */ +#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) \ + (get_precondition_function ((NODE))) + +/* For a FUNCTION_DECL of a guarded function, this holds the function decl + where post contract checks are emitted. */ +#define DECL_POST_FN(NODE) \ + (get_postcondition_function ((NODE))) + +/* True iff the FUNCTION_DECL is the pre function for a guarded function. */ +#define DECL_IS_PRE_FN_P(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_ABSTRACT_ORIGIN (NODE) && DECL_POST_FN (DECL_ABSTRACT_ORIGIN (NODE)) == NODE) + +extern void remove_contract_attributes (tree); +extern void copy_contract_attributes (tree, tree); +extern void remap_contracts (tree, tree, tree, bool); +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 void duplicate_contracts (tree, tree); +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 void set_contract_functions (tree, tree, tree); +extern tree build_contract_check (tree); +extern void emit_assertion (tree); + +#endif /* ! GCC_CP_CONTRACT_H */ |