public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/c++-contracts] c++: implement P1492 contracts
@ 2021-07-06 20:43 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2021-07-06 20:43 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:3920778fb8240cb22f9ff95cfe7d796530d40175

commit 3920778fb8240cb22f9ff95cfe7d796530d40175
Author: Jeff Chapman II <jchapman@lock3software.com>
Date:   Tue Jun 29 16:52:56 2021 -0400

    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.
    
    gcc/c-family/ChangeLog:
    
            * c-cppbuiltin.c (c_cpp_builtins): Add feature test macros
            for contracts features.
            * c.opt (contracts): Enable contracts.
            (contract-assumption-mode): Allow assumptions to be assumed.
            (contract-strict-declarations): Require contracts on the first
            declaration. Also, allow out-of-class redeclaration of members.
            (contract-mode): Enable or disable contracts.
            (contract-continuation-mode): Allow contracts to resume after
            invoking the violation handler.
            (contract-role): Specifies semantics for a role label applied to
            contracts.
            (contract-semantic): Specifies the concrete semantic for a level.
    
    gcc/cp/ChangeLog:
    
            * Make-lang.in: Add contracts.cc to the build.
            * constexpr.c (cxx_eval_constant_expression): Support constexpr
            checking of contracts.
            (potential_constant_expression_1): Add cases for contracts.
            * contracts.h: New.
            * contracts.cc: New. Implements much of the semantic support for
            contracts.
            * cp-gimplify.c (cp_genericize_r): Emit code for contract checking
            statements.
            * cp-objcp-common.c (cp_tree_size): Add contract nodes.
            (cp_handle_option): Handle contracts-related options.
            * cp-tree.def: Add new statement nodes for contract attributes.
            * cp-tree.h: Add a bunch of new macros and functions for working
            with contracts.
            (saved_scope): Add a processing to specify that the parser is working
            with contract attributes outside of a function's parameter list.
            (comparing_override_contracts): Add a global to alter the behavior
            of cp_tree_equal when comparing contracts of overrides.
            * decl.c (diagnose_misapplied_contracts): New.
            (friend_attributes): Implicitly pass attributes from grokdeclarator to
            duplicate_decls.
            (duplicate_contracts): New.
            (duplicate_decls): Compare contracts when duplicating. Diagnose various
            mismatching errors.
            (start_decl): Support redeclarations of members outside of classes.
            (grokfndecl): Rebuild postconditions after the return type is likely
            known (except when it is deduced).
            (grokdeclarator): Diagnose the application of contracts outside of
            functions. Also, make sure to attach contracts to the function
            declaration, not its type. Suppress warnings about contracts on friends
            since they're potentially used for declaration matching.
            (start_preparsed_function): Build contract checking functions at the
            start of a function definition.
            (finish_constructor_body): Emit postconditions directly into the
            body of a constructor.
            (begin_destructor_body, finish_destructor_body): Emit
            pre/postconditions directly into the bodyof a destructor.
            (finish_function_contracts): Synthesize functions to check
            preconditions and postconditions.
            * decl2.c (cp_check_const_attributes): Skip contracts.
            (cp_tree_defined_r, cp_tree_defined): New. Ensure that functions and
            variables used in pre/post are defined.
            * error.c (dump_type): Prevent crashes when the type is unnamed.
            * except.c (init_exception_processing): Build contract violation
            handlers.
            * mangle.c (write_encoding): Add .pre and .post to checking
            functions.
            * module.cc (fn_parms_init): Serialize contracts and pre/post
            checking functions.
            (check_mergeable_decl): Reject functions with invalid contracts.
            * parser.c (make_call_declarator): Pass standard attributes to the
            call declarator.
            (cp_parser_constant_expression): Cleanup redundant code by calling
            cp_parser_conditional_expression.
            (unparsed_contracts): New queue for late-parsed contracts.
            (push_unparsed_function_queues): Update initializer.
            (cp_parser_new): Initialize new declaring_friend_p flag.
            (cp_parser_statement): Check for invalid contract attributes and handle
            assertions.
            (cp_parser_decl_specifier_seq, cp_parser_class_head): Check for
            misapplied contracts.
            (cp_parser_direct_declarator) Note when we're parsing a friend
            declaration. This is needed to prevent deferred parsing of contract
            attributes.
            (cp_parser_class_specifier_1): Handle late-parsed contracts.
            (cp_parser_std_attribute_spec): Parse contracts.
            (cp_parser_member_declaration, cp_parser_late_parsing_for_member): Push
            deferred contracts.
            (cp_contract_assertion_p, function_declarator_p,
            find_innermost_function_declarator, cp_parser_late_contract_condition,
            cp_parser_skip_up_to_closing_square_bracket, contract_attribute_p,
            cp_parser_conditional_expression, cp_parser_contract_role,
            cp_parser_contract_mode_opt, find_error, contains_error_p,
            cp_parser_contract_attribute_spec): New. Support the parsing contracs.
            * parser.h (cp_unparsed_functions_entry): Add queue for contracts.
            (cp_parser): Add flag for processing friend declarations.
            * pt.c (register_parameter_specializations): Make non-static.
            (register_local_identity): New. Used when rebuilding postconditions.
            (remove_contracts_from_specialization): New. Ensure that
            specializations don't inherit contracts from their more general
            template.
            (tsubst_contract, tsubst_contract_attribute,
            tsubst_contract_attributes): New.
            (tsubst_copy): Allow parameters outside of parameter lists.
            (tsubst_expr): Substitute through assertions.
            (tsubst_copy_and_build): Re-enable handling FLOAT_EXPRs since
            they still occur in the contract test suite.
            (regenerate_decl_from_template): Instantiate contract attributes
            as needed.
            * search.c (inherit_base_contracts): New. Copy base function
            contracts onto an override.
            (check_final_overrider): Check that contracts match by pushing a
            deferred check.
            * semantics.c (decl_pre_fn, decl_post_fn, decl_original_fn,
            get_precondition_function, get_postcondition_function,
            set_precondition_function, set_postcondition_function,
            set_contract_functions, get_contracts_original_fn,
            set_contracts_original_fn): New. Manage associations between guarded
            functions and their pre/post checking functions.
            (build_arg_list, copy_fn_decl, build_contract_condition_function,
            build_contract_condition_function, has_active_contract_condition,
            has_active_preconditions, has_active_postconditions,
            build_precondition_function, build_postcondition_function,
            build_contract_function_decls): New. Create pre/post checking functions
            for a guarded function.
            (start_postcondition_statement, finish_postcondition_statement): New.
            Build postconditions.
            (get_contract_level_name, get_contract_role_name,
            build_contract_handler_fn, contract_active_p, contract_any_active_p,
            build_contract_check, emit_contract_statement,
            emit_contract_conditions, emit_assertion, emit_preconditions,
            emit_postconditions, finish_contract_condition): New. Emit checking
            for individual contract attributes.
            (finish_return_stmt): Simplify checks. Emit postconditions directly.
            (finish_non_static_data_member): Add checks for contracts referring
            to members in constructors and destructors.
            (process_outer_var_ref): Allow parameter usage in contract attributes.
            (finish_id_expression_1): Similarly.
            (apply_deduced_return_type): Rebuild postconditions once the return
            type has been deduced.
            * tree.c (comparing_override_contracts, get_innermost_component,
            is_this_expression, comparing_this_references,
            equivalent_member_references): New. Define expression equivalence for
            contract conditions that refer to the same members, possibly through
            different paths. Needed for contract matching with overrides.
            (cp_tree_equal): Compare expressions differently when comparing
            override and base function contracts.
            (std_attribute_table): Add entries for pre and post.
            (handle_contract_attribute): New.
            * typeck.c (apply_postcondition_to_return): New. Wrap a return a call
            to the postcondition.
            (check_return_expr): Use the function above.
    
    gcc/ChangeLog:
    
            * input.c (get_source): New. Return the source text for a
            particular location in a file.
            * input.h (get_source): Declare.
    
    libstdc++-v3/ChangeLog:
    
            * config/abi/pre/gnu.ver: List symbols exported for contracts.
            * include/Makefile.am: Add the contract header to the build.
            * include/std/contract: New standard header.
            * src/c++17/Makefile.am: Add contracts.cc.
            * src/c++17/contract.cc: New implementation file for contracts.
            * include/Makefile.in: Regenerate.
            * src/c++17/Makefile.in: Regenerate.
    
    gcc/testsuite/ChangeLog:
    
            * contracts/backtrace_handler/assert_fail.cpp: New test.
            * contracts/backtrace_handler/handle_contract_violation.cpp: New test.
            * contracts/except_preload_handler/assert_fail.cpp: New test.
            * contracts/except_preload_handler/handle_contract_violation.cpp:
            New test.
            * contracts/noexcept_preload_handler/assert_fail.cpp: New test.
            * contracts/noexcept_preload_handler/handle_contract_violation.cpp:
            New test.
            * contracts/preload_handler/assert_fail.cpp: New test.
            * contracts/preload_handler/handle_contract_violation.cpp: New test.
            * contracts/preload_nocontinue_handler/assert_fail.cpp: New test.
            * contracts/preload_nocontinue_handler/handle_contract_violation.cpp:
            New test.
            * contracts/preload_nocontinue_handler/nocontinue.cpp: New test.
            * g++.dg/cpp2a/contracts-access1.C: New test.
            * g++.dg/cpp2a/contracts-assume1.C: New test.
            * g++.dg/cpp2a/contracts-assume2.C: New test.
            * g++.dg/cpp2a/contracts-assume3.C: New test.
            * g++.dg/cpp2a/contracts-assume4.C: New test.
            * g++.dg/cpp2a/contracts-assume5.C: New test.
            * g++.dg/cpp2a/contracts-assume6.C: New test.
            * g++.dg/cpp2a/contracts-config1.C: New test.
            * g++.dg/cpp2a/contracts-constexpr1.C: New test.
            * g++.dg/cpp2a/contracts-constexpr2.C: New test.
            * g++.dg/cpp2a/contracts-conversion1.C: New test.
            * g++.dg/cpp2a/contracts-ctor-dtor1.C: New test.
            * g++.dg/cpp2a/contracts-ctor-dtor2.C: New test.
            * g++.dg/cpp2a/contracts-cv1.C: New test.
            * g++.dg/cpp2a/contracts-deduced1.C: New test.
            * g++.dg/cpp2a/contracts-deduced2.C: New test.
            * g++.dg/cpp2a/contracts-friend1.C: New test.
            * g++.dg/cpp2a/contracts-ft1.C: New test.
            * g++.dg/cpp2a/contracts-ignore1.C: New test.
            * g++.dg/cpp2a/contracts-ignore2.C: New test.
            * g++.dg/cpp2a/contracts-large-return.C: New test.
            * g++.dg/cpp2a/contracts-multiple-inheritance1.C: New test.
            * g++.dg/cpp2a/contracts-multiple-inheritance2.C: New test.
            * g++.dg/cpp2a/contracts-nested-class1.C: New test.
            * g++.dg/cpp2a/contracts-nested-class2.C: New test.
            * g++.dg/cpp2a/contracts-override.C: New test.
            * g++.dg/cpp2a/contracts-post1.C: New test.
            * g++.dg/cpp2a/contracts-post2.C: New test.
            * g++.dg/cpp2a/contracts-post3.C: New test.
            * g++.dg/cpp2a/contracts-post4.C: New test.
            * g++.dg/cpp2a/contracts-post5.C: New test.
            * g++.dg/cpp2a/contracts-post6.C: New test.
            * g++.dg/cpp2a/contracts-pre1.C: New test.
            * g++.dg/cpp2a/contracts-pre10.C: New test.
            * g++.dg/cpp2a/contracts-pre2.C: New test.
            * g++.dg/cpp2a/contracts-pre2a1.C: New test.
            * g++.dg/cpp2a/contracts-pre2a2.C: New test.
            * g++.dg/cpp2a/contracts-pre3.C: New test.
            * g++.dg/cpp2a/contracts-pre4.C: New test.
            * g++.dg/cpp2a/contracts-pre5.C: New test.
            * g++.dg/cpp2a/contracts-pre6.C: New test.
            * g++.dg/cpp2a/contracts-pre7.C: New test.
            * g++.dg/cpp2a/contracts-pre9.C: New test.
            * g++.dg/cpp2a/contracts-redecl1.C: New test.
            * g++.dg/cpp2a/contracts-redecl2.C: New test.
            * g++.dg/cpp2a/contracts-redecl3.C: New test.
            * g++.dg/cpp2a/contracts-redecl4.C: New test.
            * g++.dg/cpp2a/contracts-redecl5.C: New test.
            * g++.dg/cpp2a/contracts-redecl6.C: New test.
            * g++.dg/cpp2a/contracts-redecl7.C: New test.
            * g++.dg/cpp2a/contracts-redecl8.C: New test.
            * g++.dg/cpp2a/contracts-tmpl-attr1.C: New test.
            * g++.dg/cpp2a/contracts-tmpl-spec1.C: New test.
            * g++.dg/cpp2a/contracts-tmpl-spec2.C: New test.
            * g++.dg/cpp2a/contracts-tmpl-spec3.C: New test.
            * g++.dg/cpp2a/contracts1.C: New test.
            * g++.dg/cpp2a/contracts10.C: New test.
            * g++.dg/cpp2a/contracts11.C: New test.
            * g++.dg/cpp2a/contracts12.C: New test.
            * g++.dg/cpp2a/contracts13.C: New test.
            * g++.dg/cpp2a/contracts14.C: New test.
            * g++.dg/cpp2a/contracts15.C: New test.
            * g++.dg/cpp2a/contracts16.C: New test.
            * g++.dg/cpp2a/contracts17.C: New test.
            * g++.dg/cpp2a/contracts18.C: New test.
            * g++.dg/cpp2a/contracts19.C: New test.
            * g++.dg/cpp2a/contracts2.C: New test.
            * g++.dg/cpp2a/contracts20.C: New test.
            * g++.dg/cpp2a/contracts22.C: New test.
            * g++.dg/cpp2a/contracts24.C: New test.
            * g++.dg/cpp2a/contracts25.C: New test.
            * g++.dg/cpp2a/contracts3.C: New test.
            * g++.dg/cpp2a/contracts35.C: New test.
            * g++.dg/cpp2a/contracts4.C: New test.
            * g++.dg/cpp2a/contracts5.C: New test.
            * g++.dg/cpp2a/contracts6.C: New test.
            * g++.dg/cpp2a/contracts7.C: New test.
            * g++.dg/cpp2a/contracts8.C: New test.
            * g++.dg/cpp2a/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.
            * contracts/backtrace_handler/example_out.txt: New test.
            * contracts/backtrace_handler/example_pretty.txt: New test.
            * contracts/backtrace_handler/prettytrace.sh: New test.
            * contracts/backtrace_handler/Makefile: New test.
            * contracts/backtrace_handler/README: New test.
            * contracts/except_preload_handler/Makefile: New test.
            * contracts/except_preload_handler/README: New test.
            * contracts/noexcept_preload_handler/Makefile: New test.
            * contracts/noexcept_preload_handler/README: New test.
            * contracts/preload_handler/Makefile: New test.
            * contracts/preload_handler/README: New test.
            * contracts/preload_nocontinue_handler/Makefile: New test.
            * contracts/preload_nocontinue_handler/README: New test.
    
    Co-authored-by: Andrew Sutton  <asutton@lock3software.com>
    Co-authored-by: Andrew Marmaduke <amarmaduke@lock3software.com>
    Co-authored-by: Michael Lopez <mlopez@lock3software.com>

Diff:
---
 gcc/c-family/c.opt                                 |   41 +
 gcc/cp/contracts.h                                 |  165 +++
 gcc/cp/cp-tree.h                                   |  231 ++++
 gcc/cp/parser.h                                    |    8 +
 gcc/input.h                                        |    1 +
 gcc/c-family/c-cppbuiltin.c                        |    6 +
 gcc/cp/constexpr.c                                 |   31 +
 gcc/cp/contracts.cc                                | 1263 ++++++++++++++++++++
 gcc/cp/cp-gimplify.c                               |   24 +
 gcc/cp/cp-objcp-common.c                           |   41 +
 gcc/cp/decl.c                                      |  410 ++++++-
 gcc/cp/decl2.c                                     |   25 +
 gcc/cp/error.c                                     |    3 +-
 gcc/cp/except.c                                    |   19 +
 gcc/cp/mangle.c                                    |   10 +
 gcc/cp/module.cc                                   |   34 +-
 gcc/cp/parser.c                                    |  613 +++++++++-
 gcc/cp/pt.c                                        |  200 +++-
 gcc/cp/search.c                                    |   60 +
 gcc/cp/semantics.c                                 |  568 ++++++++-
 gcc/cp/tree.c                                      |   65 +
 gcc/cp/typeck.c                                    |   39 +
 gcc/input.c                                        |   83 ++
 .../contracts/backtrace_handler/assert_fail.cpp    |   23 +
 .../handle_contract_violation.cpp                  |   26 +
 .../except_preload_handler/assert_fail.cpp         |   20 +
 .../handle_contract_violation.cpp                  |   14 +
 .../noexcept_preload_handler/assert_fail.cpp       |   20 +
 .../handle_contract_violation.cpp                  |   14 +
 .../contracts/preload_handler/assert_fail.cpp      |    7 +
 .../preload_handler/handle_contract_violation.cpp  |   15 +
 .../preload_nocontinue_handler/assert_fail.cpp     |   10 +
 .../handle_contract_violation.cpp                  |   13 +
 .../preload_nocontinue_handler/nocontinue.cpp      |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts-access1.C     |  128 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-assume1.C     |   30 +
 gcc/testsuite/g++.dg/cpp2a/contracts-assume2.C     |   34 +
 gcc/testsuite/g++.dg/cpp2a/contracts-assume3.C     |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts-assume4.C     |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts-assume5.C     |   35 +
 gcc/testsuite/g++.dg/cpp2a/contracts-assume6.C     |   61 +
 gcc/testsuite/g++.dg/cpp2a/contracts-config1.C     |   36 +
 gcc/testsuite/g++.dg/cpp2a/contracts-constexpr1.C  |   74 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-constexpr2.C  |   58 +
 gcc/testsuite/g++.dg/cpp2a/contracts-conversion1.C |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor1.C  |  177 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor2.C  |   35 +
 gcc/testsuite/g++.dg/cpp2a/contracts-cv1.C         |   37 +
 gcc/testsuite/g++.dg/cpp2a/contracts-deduced1.C    |  108 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-deduced2.C    |   84 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-friend1.C     |   36 +
 gcc/testsuite/g++.dg/cpp2a/contracts-ft1.C         |   14 +
 gcc/testsuite/g++.dg/cpp2a/contracts-ignore1.C     |   30 +
 gcc/testsuite/g++.dg/cpp2a/contracts-ignore2.C     |   26 +
 .../g++.dg/cpp2a/contracts-large-return.C          |   15 +
 .../g++.dg/cpp2a/contracts-multiple-inheritance1.C |   15 +
 .../g++.dg/cpp2a/contracts-multiple-inheritance2.C |   33 +
 .../g++.dg/cpp2a/contracts-nested-class1.C         |   27 +
 .../g++.dg/cpp2a/contracts-nested-class2.C         |   40 +
 gcc/testsuite/g++.dg/cpp2a/contracts-override.C    |   43 +
 gcc/testsuite/g++.dg/cpp2a/contracts-post1.C       |   74 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-post2.C       |   13 +
 gcc/testsuite/g++.dg/cpp2a/contracts-post3.C       |   15 +
 gcc/testsuite/g++.dg/cpp2a/contracts-post4.C       |   36 +
 gcc/testsuite/g++.dg/cpp2a/contracts-post5.C       |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts-post6.C       |   29 +
 gcc/testsuite/g++.dg/cpp2a/contracts-pre1.C        |   36 +
 gcc/testsuite/g++.dg/cpp2a/contracts-pre10.C       |  190 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre2.C        |  212 ++++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre2a1.C      |   33 +
 gcc/testsuite/g++.dg/cpp2a/contracts-pre2a2.C      |   22 +
 gcc/testsuite/g++.dg/cpp2a/contracts-pre3.C        |  525 ++++++++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre4.C        |   92 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre5.C        |   81 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre6.C        |   74 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre7.C        |  134 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-pre9.C        |  146 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl1.C     |  149 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl2.C     |  150 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl3.C     |  195 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl4.C     |   56 +
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl5.C     |  101 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl6.C     |  195 +++
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl7.C     |   64 +
 gcc/testsuite/g++.dg/cpp2a/contracts-redecl8.C     |   65 +
 gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-attr1.C  |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec1.C  |  121 ++
 gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec2.C  |  395 ++++++
 gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec3.C  |   45 +
 gcc/testsuite/g++.dg/cpp2a/contracts1.C            |   49 +
 gcc/testsuite/g++.dg/cpp2a/contracts10.C           |   73 ++
 gcc/testsuite/g++.dg/cpp2a/contracts11.C           |  103 ++
 gcc/testsuite/g++.dg/cpp2a/contracts12.C           |   15 +
 gcc/testsuite/g++.dg/cpp2a/contracts13.C           |   51 +
 gcc/testsuite/g++.dg/cpp2a/contracts14.C           |   81 ++
 gcc/testsuite/g++.dg/cpp2a/contracts15.C           |   79 ++
 gcc/testsuite/g++.dg/cpp2a/contracts16.C           |   34 +
 gcc/testsuite/g++.dg/cpp2a/contracts17.C           |   35 +
 gcc/testsuite/g++.dg/cpp2a/contracts18.C           |   15 +
 gcc/testsuite/g++.dg/cpp2a/contracts19.C           |   19 +
 gcc/testsuite/g++.dg/cpp2a/contracts2.C            |   13 +
 gcc/testsuite/g++.dg/cpp2a/contracts20.C           |   11 +
 gcc/testsuite/g++.dg/cpp2a/contracts22.C           |   32 +
 gcc/testsuite/g++.dg/cpp2a/contracts24.C           |   15 +
 gcc/testsuite/g++.dg/cpp2a/contracts25.C           |   57 +
 gcc/testsuite/g++.dg/cpp2a/contracts3.C            |   13 +
 gcc/testsuite/g++.dg/cpp2a/contracts35.C           |   47 +
 gcc/testsuite/g++.dg/cpp2a/contracts4.C            |   11 +
 gcc/testsuite/g++.dg/cpp2a/contracts5.C            |   13 +
 gcc/testsuite/g++.dg/cpp2a/contracts6.C            |   11 +
 gcc/testsuite/g++.dg/cpp2a/contracts7.C            |   14 +
 gcc/testsuite/g++.dg/cpp2a/contracts8.C            |   43 +
 gcc/testsuite/g++.dg/cpp2a/contracts9.C            |   45 +
 gcc/testsuite/g++.dg/modules/contracts-1_a.C       |   46 +
 gcc/testsuite/g++.dg/modules/contracts-1_b.C       |   33 +
 gcc/testsuite/g++.dg/modules/contracts-2_a.C       |   49 +
 gcc/testsuite/g++.dg/modules/contracts-2_b.C       |   35 +
 gcc/testsuite/g++.dg/modules/contracts-2_c.C       |   22 +
 gcc/testsuite/g++.dg/modules/contracts-3_a.C       |   41 +
 gcc/testsuite/g++.dg/modules/contracts-3_b.C       |   35 +
 gcc/testsuite/g++.dg/modules/contracts-4_a.C       |   28 +
 gcc/testsuite/g++.dg/modules/contracts-4_b.C       |    8 +
 gcc/testsuite/g++.dg/modules/contracts-4_c.C       |    9 +
 gcc/testsuite/g++.dg/modules/contracts-4_d.C       |   22 +
 .../g++.dg/modules/contracts-tpl-friend-1_a.C      |   17 +
 .../g++.dg/modules/contracts-tpl-friend-1_b.C      |   19 +
 libstdc++-v3/src/c++17/contract.cc                 |  136 +++
 gcc/cp/Make-lang.in                                |    2 +-
 gcc/cp/cp-tree.def                                 |   11 +
 .../contracts/backtrace_handler/example_out.txt    |   12 +
 .../contracts/backtrace_handler/example_pretty.txt |    8 +
 .../contracts/backtrace_handler/prettytrace.sh     |   30 +
 libstdc++-v3/config/abi/pre/gnu.ver                |   12 +
 libstdc++-v3/include/Makefile.am                   |    1 +
 libstdc++-v3/include/Makefile.in                   |    1 +
 libstdc++-v3/src/c++17/Makefile.am                 |    1 +
 libstdc++-v3/src/c++17/Makefile.in                 |    5 +-
 gcc/testsuite/contracts/backtrace_handler/Makefile |   13 +
 gcc/testsuite/contracts/backtrace_handler/README   |   12 +
 .../contracts/except_preload_handler/Makefile      |   13 +
 .../contracts/except_preload_handler/README        |   13 +
 .../contracts/noexcept_preload_handler/Makefile    |   13 +
 .../contracts/noexcept_preload_handler/README      |   15 +
 gcc/testsuite/contracts/preload_handler/Makefile   |   13 +
 gcc/testsuite/contracts/preload_handler/README     |    2 +
 .../contracts/preload_nocontinue_handler/Makefile  |   23 +
 .../contracts/preload_nocontinue_handler/README    |   23 +
 libstdc++-v3/include/std/contract                  |   76 ++
 148 files changed, 10251 insertions(+), 67 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 91929706aff..ac770f2d02c 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1582,6 +1582,47 @@ fconstexpr-ops-limit=
 C++ ObjC++ Joined RejectNegative Host_Wide_Int Var(constexpr_ops_limit) Init(33554432)
 -fconstexpr-ops-limit=<number>	Specify maximum number of constexpr operations during a single constexpr evaluation.
 
+fcontracts
+C++ ObjC++ Var(flag_contracts) Init(0)
+Enable certain features present drafts of C++ Contracts.
+
+Enum
+Name(on_off) Type(int) UnknownError(argument %qs must be either %<on%> or %<off%>)
+
+EnumValue
+Enum(on_off) String(off) Value(0)
+
+EnumValue
+Enum(on_off) String(on) Value(1)
+
+fcontract-assumption-mode=
+C++ Joined
+-fcontract-assumption-mode=[on|off]	Enable or disable treating axiom level contracts as assumptions (default on).
+
+fcontract-build-level=
+C++ Joined RejectNegative
+-fcontract-build-level=[off|default|audit]	Specify max contract level to generate runtime checks for
+
+fcontract-strict-declarations=
+C++ Var(flag_contract_strict_declarations) Enum(on_off) Joined Init(0) RejectNegative
+-fcontract-strict-declarations=[on|off]	Enable or disable warnings on generalized redeclaration of functions with contracts (default off).
+
+fcontract-mode=
+C++ Var(flag_contract_mode) Enum(on_off) Joined Init(1) RejectNegative
+-fcontract-mode=[on|off]	Enable or disable all contract facilities (default on).
+
+fcontract-continuation-mode=
+C++ Joined
+-fcontract-continuation-mode=[on|off]	Enable or disable contract continuation mode (default off).
+
+fcontract-role=
+C++ Joined
+-fcontract-role=<name>:<semantics>	Specify the semantics for all levels in a role (default, review), or a custom contract role with given semantics (ex: opt:assume,assume,assume)
+
+fcontract-semantic=
+C++ Joined
+-fcontract-semantic=<level>:<semantic>	Specify the concrete semantics for level
+
 fcoroutines
 C++ LTO Var(flag_coroutines)
 Enable C++ coroutines (experimental).
diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h
new file mode 100644
index 00000000000..3ae0d01c8bf
--- /dev/null
+++ b/gcc/cp/contracts.h
@@ -0,0 +1,165 @@
+/* Definitions for C++ contract levels.  Implements functionality described in
+   the working draft version of contracts, P1290, P1332, and P1429.
+   Copyright (C) 2020 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;
+}
+
+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);
+
+/* 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 *);
+
+#endif /* ! GCC_CP_CONTRACT_H */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ac6264dd8c1..4a1ac2769c7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "hard-reg-set.h"
 #include "function.h"
+#include "contracts.h"
 
 /* In order for the format checking to accept the C++ front end
    diagnostic framework extensions, you must include this file before
@@ -222,6 +223,9 @@ enum cp_tree_index
     CPTI_DSO_HANDLE,
     CPTI_DCAST,
 
+    CPTI_ON_CONTRACT_VIOLATION,
+    CPTI_ON_CONTRACT_VIOLATION_NEVER,
+
     CPTI_SOURCE_LOCATION_IMPL,
 
     CPTI_FALLBACK_DFLOAT32_TYPE,
@@ -361,6 +365,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define throw_fn			cp_global_trees[CPTI_THROW_FN]
 #define rethrow_fn			cp_global_trees[CPTI_RETHROW_FN]
 
+#define on_contract_violation_fn        cp_global_trees[CPTI_ON_CONTRACT_VIOLATION]
+#define on_contract_violation_never_fn  cp_global_trees[CPTI_ON_CONTRACT_VIOLATION_NEVER]
+
 /* The type of the function-pointer argument to "__cxa_atexit" (or
    "std::atexit", if "__cxa_atexit" is not being used).  */
 #define atexit_fn_ptr_type_node         cp_global_trees[CPTI_ATEXIT_FN_PTR_TYPE]
@@ -450,6 +457,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR)
       OVL_DEDUP_P (in OVERLOAD)
       ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR)
+      contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
    1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -485,6 +493,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR)
       IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR)
       PACK_EXPANSION_AUTO_P (in *_PACK_EXPANSION)
+      contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
    3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR)
       ICS_BAD_FLAG (in _CONV)
       FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -494,6 +503,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR)
       OVL_NESTED_P (in OVERLOAD)
       DECL_MODULE_EXPORT_P (in _DECL)
+      contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
    4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
 	  CALL_EXPR, or FIELD_DECL).
@@ -1338,6 +1348,90 @@ 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;
@@ -1816,6 +1910,8 @@ struct GTY(()) saved_scope {
   BOOL_BITFIELD x_processing_explicit_instantiation : 1;
   BOOL_BITFIELD need_pop_function_context : 1;
 
+  int x_processing_contract_condition;
+
   /* Nonzero if we are parsing the discarded statement of a constexpr
      if-statement.  */
   BOOL_BITFIELD discarded_stmt : 1;
@@ -1884,6 +1980,12 @@ extern GTY(()) struct saved_scope *scope_chain;
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
 
+/* Nonzero if we are parsing the conditional expression of a contract
+   condition. These expressions appear outside the paramter list (like a
+   trailing return type), but are potentially evaluated.  */
+
+#define processing_contract_condition scope_chain->x_processing_contract_condition
+
 #define in_discarded_stmt scope_chain->discarded_stmt
 #define in_consteval_if_p scope_chain->consteval_if_p
 
@@ -3087,6 +3189,14 @@ struct GTY(()) lang_decl {
   (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (NODE)            \
    || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (NODE))
 
+/* Nonzero if NODE (a FUNCTION_DECL) is a ctor or dtor that needs the cdtor
+   label and associated goto built.  */
+#define DECL_CDTOR_NEEDS_LABLED_EXIT_P(NODE)            \
+  (DECL_DESTRUCTOR_P (NODE)                             \
+   || (DECL_CONSTRUCTOR_P (NODE)       \
+       && (targetm.cxx.cdtor_returns_this ()            \
+	   || contract_any_active_p (DECL_CONTRACTS (NODE)))))
+
 /* Nonzero if NODE (a _DECL) is a cloned constructor or
    destructor.  */
 #define DECL_CLONED_FUNCTION_P(NODE)		\
@@ -3575,6 +3685,64 @@ struct GTY(()) lang_decl {
 #define DECL_PENDING_INLINE_INFO(NODE) \
   (LANG_DECL_FN_CHECK (NODE)->u.pending_inline_info)
 
+/* Return the first contract in ATTRS, or NULL_TREE if there are none.  */
+
+inline tree
+find_contract (tree attrs)
+{
+  while (attrs && !cxx_contract_attribute_p (attrs))
+    attrs = TREE_CHAIN (attrs);
+  return attrs;
+}
+
+/* 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)))
+
+/* 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)))
+
+/* For a FUNCTION_DECL of a pre/post function, this points back to the
+   original guarded function.  */
+#define DECL_ORIGINAL_FN(NODE) \
+  (get_contracts_original_fn (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)
+
+/* 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)
+
 /* Nonzero for TYPE_DECL means that it was written 'using name = type'.  */
 #define TYPE_DECL_ALIAS_P(NODE) \
   DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE))
@@ -5489,6 +5657,11 @@ extern int comparing_specializations;
    FIXME we should always do this except during deduction/ordering.  */
 extern int comparing_dependent_aliases;
 
+/* Nonzero if we want to consider different member expressions to compare
+   equal if they designate the same entity. This is set when comparing
+   contract conditions of overrides.  */
+extern bool comparing_override_contracts;
+
 /* In parser.c.  */
 
 /* Nonzero if we are parsing an unevaluated operand: an operand to
@@ -6667,6 +6840,7 @@ 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);
@@ -6788,6 +6962,7 @@ extern void import_export_decl			(tree);
 extern tree build_cleanup			(tree);
 extern tree build_offset_ref_call_from_tree	(tree, vec<tree, va_gc> **,
 						 tsubst_flags_t);
+extern bool cp_tree_defined_p			(tree);
 extern bool decl_defined_p			(tree);
 extern bool decl_constant_var_p			(tree);
 extern bool decl_maybe_constant_var_p		(tree);
@@ -7096,6 +7271,8 @@ extern void inject_this_parameter (tree, cp_cv_quals);
 extern location_t defparse_location (tree);
 extern void maybe_show_extern_c_location (void);
 extern bool literal_integer_zerop (const_tree);
+extern bool function_declarator_p (const cp_declarator *);
+extern const cp_declarator *find_innermost_function_declarator (const cp_declarator *);
 
 /* in pt.c */
 extern tree canonical_type_parameter		(tree);
@@ -7269,8 +7446,10 @@ extern hashval_t iterative_hash_template_arg	(tree arg, hashval_t val);
 extern tree coerce_template_parms               (tree, tree, tree);
 extern tree coerce_template_parms               (tree, tree, tree, tsubst_flags_t);
 extern tree canonicalize_type_argument		(tree, tsubst_flags_t);
+extern void register_local_identity		(tree);
 extern void register_local_specialization       (tree, tree);
 extern tree retrieve_local_specialization       (tree);
+extern void register_parameter_specializations	(tree, tree);
 extern tree extract_fnparm_pack                 (tree, tree *);
 extern tree template_parm_to_arg                (tree);
 extern tree dguide_name				(tree);
@@ -7371,6 +7550,58 @@ extern bool perform_or_defer_access_check	(tree, tree, tree,
 						 tsubst_flags_t,
 						 access_failure_info *afi = NULL);
 
+/* contracts.cc */
+enum contract_matching_context
+{
+  cmc_declaration,
+  cmc_override
+};
+
+extern tree invalidate_contract			(tree);
+extern tree make_postcondition_variable		(cp_expr);
+extern tree make_postcondition_variable		(cp_expr, tree);
+extern bool check_postcondition_result		(tree, tree, location_t);
+extern void rebuild_postconditions		(tree, tree);
+extern tree grok_contract			(tree, tree, tree, cp_expr, location_t);
+extern tree finish_contract_attribute		(tree, tree);
+extern void update_late_contract		(tree, tree, tree);
+extern tree finish_contract_condition		(cp_expr);
+extern void remove_contract_attributes		(tree);
+extern void copy_contract_attributes		(tree, tree);
+extern tree splice_out_contracts		(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 void set_contracts_original_fn		(tree, tree);
+extern tree start_postcondition_statement	();
+extern void finish_postcondition_statement	(tree);
+extern tree build_contract_check		(tree);
+extern vec<tree, va_gc> *build_arg_list		(tree);
+extern tree get_postcondition_result_parameter	(tree);
+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			(tree);
+
+inline void
+set_decl_contracts (tree decl, tree contract_attrs)
+{
+  remove_contract_attributes (decl);
+  DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), contract_attrs);
+}
+
 /* RAII sentinel to ensures that deferred access checks are popped before
   a function returns.  */
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 187d0ccc665..2ee028ce350 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -174,6 +174,9 @@ struct GTY(()) cp_unparsed_functions_entry {
 
   /* Functions with noexcept-specifiers that require post-processing.  */
   vec<tree, va_gc> *noexcepts;
+
+  /* Functions with contract attributes that require post-processing.  */
+  vec<tree, va_gc> *contracts;
 };
 
 
@@ -309,6 +312,11 @@ struct GTY(()) cp_parser {
      direct-declarator.  */
   bool in_declarator_p;
 
+  /* 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.  */
+  bool declaring_friend_p;
+
   /* TRUE if we are presently parsing a template-argument-list.  */
   bool in_template_argument_list_p;
 
diff --git a/gcc/input.h b/gcc/input.h
index bbcec84c521..e6fd8269d36 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -86,6 +86,7 @@ class char_span
 };
 
 extern char_span location_get_source_line (const char *file_path, int line);
+extern char *get_source (location_t, location_t);
 
 extern bool location_missing_trailing_newline (const char *file_path);
 
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index f79f939bd10..3f42503f6a5 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -1038,6 +1038,12 @@ c_cpp_builtins (cpp_reader *pfile)
           else
             cpp_define (pfile, "__cpp_concepts=201507L");
         }
+      if (flag_contracts)
+	{
+	  cpp_define (pfile, "__cpp_contracts=201906L");
+	  cpp_define (pfile, "__cpp_contracts_literal_semantics=201906L");
+	  cpp_define (pfile, "__cpp_contracts_roles=201906L");
+	}
       if (flag_modules)
 	/* The std-defined value is 201907L, but I don't think we can
 	   claim victory yet.  201810 is the p1103 date. */
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 39787f3f5d5..435bf530d68 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -7013,6 +7013,30 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       r = void_node;
       break;
 
+    case ASSERTION_STMT:
+    case PRECONDITION_STMT:
+    case POSTCONDITION_STMT:
+      {
+	contract_semantic semantic = get_contract_semantic (t);
+	if (semantic == CCS_IGNORE)
+	  break;
+
+	tree c = CONTRACT_CONDITION (t);
+	if (semantic == CCS_ASSUME && !cp_tree_defined_p (c))
+	  break;
+
+	/* Evaluate the generated check.  */
+	r = cxx_eval_constant_expression (ctx, c, false, non_constant_p,
+					  overflow_p);
+	if (r == boolean_false_node)
+	  {
+	    if (!ctx->quiet)
+	      error_at (EXPR_LOCATION (c), "contract predicate %qE is %qE", c, r);
+	    *non_constant_p = true;
+	  }
+      }
+      break;
+
     case TEMPLATE_ID_EXPR:
       {
         /* We can evaluate template-id that refers to a concept only if
@@ -8921,6 +8945,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 	return false;
       }
 
+    case ASSERTION_STMT:
+    case PRECONDITION_STMT:
+    case POSTCONDITION_STMT:
+      if (!RECUR (CONTRACT_CONDITION (t), rval))
+	return false;
+      return true;
+
     case LABEL_EXPR:
       t = LABEL_EXPR_LABEL (t);
       if (DECL_ARTIFICIAL (t))
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
new file mode 100644
index 00000000000..2d005d5ab9b
--- /dev/null
+++ b/gcc/cp/contracts.cc
@@ -0,0 +1,1263 @@
+/* Definitions for C++ contract levels
+   Copyright (C) 2020 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/>.  */
+
+/* Design Notes
+
+   A function is called a "guarded" function if it has pre or post contract
+   attributes. A contract is considered an "active" contract if runtime code is
+   needed for the contract under the current contract configuration.
+
+   pre and post contract attributes are parsed and stored in DECL_ATTRIBUTES.
+   assert contracts are parsed and wrapped in statements. When genericizing, all
+   active and assumed contracts are transformed into an if block. An observed
+   contract:
+
+     [[ pre: v > 0 ]]
+
+   is transformed into:
+
+     if (!(v > 0)) {
+       __on_contract_violation (true, // continue_
+	 5, // line_number,
+	 "main.cpp", // file_name,
+	 "fun", // function_name,
+	 "v > 0", // comment,
+	 "default", // assertion_level,
+	 "default", // assertion_role,
+	 CCS_MAYBE, // continuation_mode
+	 );
+     }
+
+   Here, __on_contract_violation is a shim used to actually construct the
+   std::contract_violation and call the installed handler, finally terminating
+   if the contract should not continue on violation. This prevents requiring
+   including <contract> and simplifies building the call.
+
+   Assumed contracts have a similar transformation that results the body of the
+   if being __builtin_unreachable ();
+
+   Parsing of pre and post contract conditions need to be deferred when the
+   contracts are attached to a member function. The postcondition identifier
+   cannot be used before the deduced return type of an auto function is used,
+   except when used in a defining declaration in which case they conditions are
+   fully parsed once the body is finished (see cpp2a/contracts-deduced{1,2}.C).
+
+   A list of pre and post contracts can either be repeated in their entirety or
+   completely absent in subsequent declarations. If contract lists appear on two
+   matching declarations, their contracts have to be equivalent. In general this
+   means that anything before the colon have to be token equivalent and the
+   condition must be cp_tree_equal (primarily to allow for parameter renaming).
+
+   Contracts on overrides must match those present on (all of) the overridee(s).
+
+   Template specializations may have their own contracts. If no contracts are
+   specified on the initial specialization they're assumed to be the same as
+   the primary template. Specialization redeclarations must then match either
+   the primary template (if they were unspecified originally), or those
+   specified on the specialization.
+
+
+   For non-cdtors two functions are generated for ease of implementation and to
+   avoid some cases where code bloat may occurr. These are the DECL_PRE_FN and
+   DECL_POST_FN. Each handles checking either the set of pre or post contracts
+   of a guarded function.
+
+     int fun(int v)
+       [[ pre: v > 0 ]]
+       [[ post r: r < 0 ]]
+     {
+       return -v;
+     }
+
+   The original decl is left alone and instead calls are generated to pre/post
+   functions within the body:
+
+     void fun.pre(int v)
+     {
+       [[ assert: v > 0 ]];
+     }
+     int fun.post(int v, int __r)
+     {
+       [[ assert: __r < 0 ]];
+     }
+     int fun(int v)
+     {
+       fun.pre(v);
+       return fun.post(v, -v);
+     }
+
+   This sides steps a number of issues with having to rewrite the bodies or
+   rewrite the parsed conditions as the parameters to the original function
+   changes (as happens during redeclaration). The ultimate goal is to get
+   something that optimizes well along the lines of
+
+     int fun(int v)
+     {
+       [[ assert: v > 0 ]];
+       auto &&__r = -v;
+       goto out;
+     out:
+       [[ assert: __r < 0 ]];
+       return __r;
+     }
+
+   With the idea being that multiple return statements could collapse the
+   function epilogue after inlining the pre/post functions. clang is able
+   to collapse common function epilogues, while gcc needs -O3 -Os combined.
+   We're already doing this "manually" for cdtors due to the way they're already
+   implemented, forcing DECL_CDTOR_NEEDS_LABLED_EXIT_P to be true when the
+   cdtor has active contracts.
+
+   Directly laying the pre contracts down in the function body doesn't have
+   many issues. The post contracts may need to be repeated multiple times, once
+   for each return, or a goto epilogue would need generated similarly to cdtors.
+   For this initial implementation, generating function calls and letting
+   later optimizations decide whether to inline and duplicate the actual
+   checks or whether to collapse the shared epilogue was chosen.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "cp-tree.h"
+#include "stringpool.h"
+#include "diagnostic.h"
+#include "options.h"
+#include "contracts.h"
+#include "tree.h"
+#include "tree-inline.h"
+#include "attribs.h"
+#include "tree-iterator.h"
+#include "print-tree.h"
+
+const int max_custom_roles = 32;
+static contract_role contract_build_roles[max_custom_roles] = {
+};
+
+bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = {
+  { 0, 0, 0, 0, 0, },
+  { 0, 1, 0, 0, 0, },
+  { 0, 1, 1, 1, 1, },
+  { 0, 1, 1, 1, 1, },
+  { 0, 1, 0, 0, 1, },
+};
+
+void
+validate_contract_role (contract_role *role)
+{
+  gcc_assert (role);
+  if (!unchecked_contract_p (role->axiom_semantic))
+    error ("axiom contract semantic must be %<assume%> or %<ignore%>");
+
+  if (!valid_configs[role->default_semantic][role->audit_semantic] )
+    warning (0, "the %<audit%> semantic should be at least as strong as "
+		"the %<default%> semantic");
+}
+
+contract_semantic
+lookup_concrete_semantic (const char *name)
+{
+  if (strcmp (name, "ignore") == 0)
+    return CCS_IGNORE;
+  if (strcmp (name, "assume") == 0)
+    return CCS_ASSUME;
+  if (strcmp (name, "check_never_continue") == 0
+      || strcmp (name, "never") == 0
+      || strcmp (name, "abort") == 0)
+    return CCS_NEVER;
+  if (strcmp (name, "check_maybe_continue") == 0
+      || strcmp (name, "maybe") == 0)
+    return CCS_MAYBE;
+  error ("'%s' is not a valid explicit concrete semantic", name);
+  return CCS_INVALID;
+}
+
+/* Compare role and name up to either the NUL terminator or the first
+   occurrence of colon.  */
+
+static bool
+role_name_equal (const char *role, const char *name)
+{
+  size_t role_len = strchrnul (role, ':') - role;
+  size_t name_len = strchrnul (name, ':') - name;
+  if (role_len != name_len)
+    return false;
+  return strncmp (role, name, role_len) == 0;
+}
+
+static bool
+role_name_equal (contract_role *role, const char *name)
+{
+  if (role->name == NULL)
+    return false;
+  return role_name_equal (role->name, name);
+}
+
+contract_role *
+get_contract_role (const char *name)
+{
+  for (int i = 0; i < max_custom_roles; ++i)
+    {
+      contract_role *potential = contract_build_roles + i;
+      if (role_name_equal (potential, name))
+	return potential;
+    }
+  if (role_name_equal (name, "default") || role_name_equal (name, "review"))
+    {
+      setup_default_contract_role (false);
+      return get_contract_role (name);
+    }
+  return NULL;
+}
+
+contract_role *
+add_contract_role (const char *name,
+		   contract_semantic des,
+		   contract_semantic aus,
+		   contract_semantic axs,
+		   bool update)
+{
+  for (int i = 0; i < max_custom_roles; ++i)
+    {
+      contract_role *potential = contract_build_roles + i;
+      if (potential->name != NULL
+	  && !role_name_equal (potential, name))
+	continue;
+      if (potential->name != NULL && !update)
+	return potential;
+      potential->name = name;
+      potential->default_semantic = des;
+      potential->audit_semantic = aus;
+      potential->axiom_semantic = axs;
+      return potential;
+    }
+  return NULL;
+}
+
+enum contract_build_level { OFF, DEFAULT, AUDIT };
+static bool flag_contract_continuation_mode = false;
+static bool flag_contract_assumption_mode = true;
+static int flag_contract_build_level = DEFAULT;
+
+static bool contracts_p1332_default = false, contracts_p1332_review = false,
+  contracts_std = false, contracts_p1429 = false;
+
+static contract_semantic
+get_concrete_check ()
+{
+  return flag_contract_continuation_mode ? CCS_MAYBE : CCS_NEVER;
+}
+
+static contract_semantic
+get_concrete_axiom_semantic ()
+{
+  return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE;
+}
+
+void
+setup_default_contract_role (bool update)
+{
+  contract_semantic check = get_concrete_check ();
+  contract_semantic axiom = get_concrete_axiom_semantic ();
+  switch (flag_contract_build_level)
+    {
+      case OFF:
+	add_contract_role ("default", CCS_IGNORE, CCS_IGNORE, axiom, update);
+	add_contract_role ("review", CCS_IGNORE, CCS_IGNORE, CCS_IGNORE, update);
+	break;
+      case DEFAULT:
+	add_contract_role ("default", check, CCS_IGNORE, axiom, update);
+	add_contract_role ("review", check, CCS_IGNORE, CCS_IGNORE, update);
+	break;
+      case AUDIT:
+	add_contract_role ("default", check, check, axiom, update);
+	add_contract_role ("review", check, check, CCS_IGNORE, update);
+	break;
+    }
+}
+
+contract_semantic
+map_contract_semantic (const char *ident)
+{
+  if (strcmp (ident, "ignore") == 0)
+    return CCS_IGNORE;
+  else if (strcmp (ident, "assume") == 0)
+    return CCS_ASSUME;
+  else if (strcmp (ident, "check_never_continue") == 0)
+    return CCS_NEVER;
+  else if (strcmp (ident, "check_maybe_continue") == 0)
+    return CCS_MAYBE;
+  return CCS_INVALID;
+}
+
+contract_level
+map_contract_level (const char *ident)
+{
+  if (strcmp (ident, "default") == 0)
+    return CONTRACT_DEFAULT;
+  else if (strcmp (ident, "audit") == 0)
+    return CONTRACT_AUDIT;
+  else if (strcmp (ident, "axiom") == 0)
+    return CONTRACT_AXIOM;
+  return CONTRACT_INVALID;
+}
+
+
+void
+handle_OPT_fcontract_build_level_ (const char *arg)
+{
+  if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
+    {
+      error ("-fcontract-build-level= cannot be mixed with p1332/p1429");
+      return;
+    }
+  else
+    contracts_std = true;
+
+  if (strcmp (arg, "off") == 0)
+    flag_contract_build_level = OFF;
+  else if (strcmp (arg, "default") == 0)
+    flag_contract_build_level = DEFAULT;
+  else if (strcmp (arg, "audit") == 0)
+    flag_contract_build_level = AUDIT;
+  else
+    error ("-fcontract-build-level= must be off|default|audit");
+
+  setup_default_contract_role ();
+}
+
+void
+handle_OPT_fcontract_assumption_mode_ (const char *arg)
+{
+  if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
+    {
+      error ("-fcontract-assumption-mode= cannot be mixed with p1332/p1429");
+      return;
+    }
+  else
+    contracts_std = true;
+
+  if (strcmp (arg, "on") == 0)
+    flag_contract_assumption_mode = true;
+  else if (strcmp (arg, "off") == 0)
+    flag_contract_assumption_mode = false;
+  else
+    error ("-fcontract-assumption-mode= must be %<on%> or %<off%>");
+
+  setup_default_contract_role ();
+}
+
+void
+handle_OPT_fcontract_continuation_mode_ (const char *arg)
+{
+  if (contracts_p1332_default || contracts_p1332_review || contracts_p1429)
+    {
+      error ("-fcontract-continuation-mode= cannot be mixed with p1332/p1429");
+      return;
+    }
+  else
+    contracts_std = true;
+
+  if (strcmp (arg, "on") == 0)
+    flag_contract_continuation_mode = true;
+  else if (strcmp (arg, "off") == 0)
+    flag_contract_continuation_mode = false;
+  else
+    error ("-fcontract-continuation-mode= must be %<on%> or %<off%>");
+
+  setup_default_contract_role ();
+}
+
+void
+handle_OPT_fcontract_role_ (const char *arg)
+{
+  const char *name = arg;
+  const char *vals = strchr (name, ':');
+  if (vals == NULL)
+    {
+      error ("-fcontract-role= must be in the form role:semantics");
+      return;
+    }
+
+  contract_semantic dess = CCS_INVALID, auss = CCS_INVALID, axss = CCS_INVALID;
+  char *des = NULL, *aus = NULL, *axs = NULL;
+  des = xstrdup (vals + 1);
+
+  aus = strchr (des, ',');
+  if (aus == NULL)
+    {
+      error ("-fcontract-role= semantics must include default,audit,axiom values");
+      goto validate;
+    }
+  *aus = '\0'; // null terminate des
+  aus = aus + 1; // move past null
+
+  axs = strchr (aus, ',');
+  if (axs == NULL)
+    {
+      error ("-fcontract-role= semantics must include default,audit,axiom values");
+      goto validate;
+    }
+  *axs = '\0'; // null terminate aus
+  axs = axs + 1; // move past null
+
+  dess = lookup_concrete_semantic (des);
+  auss = lookup_concrete_semantic (aus);
+  axss = lookup_concrete_semantic (axs);
+validate:
+  free (des);
+  if (dess == CCS_INVALID || auss == CCS_INVALID || axss == CCS_INVALID)
+    return;
+
+  bool is_defalult_role = role_name_equal (name, "default");
+  bool is_review_role = role_name_equal (name, "review");
+  bool is_std_role = is_defalult_role || is_review_role;
+  if ((contracts_std && is_std_role) || (contracts_p1429 && is_defalult_role))
+    {
+      error ("-fcontract-role= cannot be mixed with std/p1429 contract flags");
+      return;
+    }
+  else if (is_std_role)
+    {
+      contracts_p1332_default |= is_defalult_role;
+      contracts_p1332_review |= is_review_role;
+    }
+
+  contract_role *role = add_contract_role (name, dess, auss, axss);
+
+  if (role == NULL)
+    {
+      // TODO: not enough space?
+      error ("-fcontract-level= too many custom roles");
+      return;
+    }
+  else
+    validate_contract_role (role);
+}
+
+void
+handle_OPT_fcontract_semantic_ (const char *arg)
+{
+  if (!strchr (arg, ':'))
+    {
+      error ("-fcontract-semantic= must be in the form level:semantic");
+      return;
+    }
+
+  if (contracts_std || contracts_p1332_default)
+    {
+      error ("-fcontract-semantic= cannot be mixed with std/p1332 contract flags");
+      return;
+    }
+  contracts_p1429 = true;
+
+  contract_role *role = get_contract_role ("default");
+  if (!role)
+    {
+      error ("-fcontract-semantic= cannot find default role");
+      return;
+    }
+
+  const char *semantic = strchr (arg, ':') + 1;
+  contract_semantic sem = lookup_concrete_semantic (semantic);
+  if (sem == CCS_INVALID)
+    return;
+
+  if (strncmp ("default:", arg, 8) == 0)
+    role->default_semantic = sem;
+  else if (strncmp ("audit:", arg, 6) == 0)
+    role->audit_semantic = sem;
+  else if (strncmp ("axiom:", arg, 6) == 0)
+    role->axiom_semantic = sem;
+  else
+    error ("-fcontract-semantic= level must be default, audit, or axiom");
+  validate_contract_role (role);
+}
+
+/* Convert a contract CONFIG into a contract_mode.  */
+
+static contract_mode
+contract_config_to_mode (tree config)
+{
+  if (config == NULL_TREE)
+    return contract_mode (CONTRACT_DEFAULT, get_default_contract_role ());
+
+  /* TREE_LIST has TREE_VALUE is a level and TREE_PURPOSE is role.  */
+  if (TREE_CODE (config) == TREE_LIST)
+    {
+      contract_role *role = NULL;
+      if (TREE_PURPOSE (config))
+	role = get_contract_role (IDENTIFIER_POINTER (TREE_PURPOSE (config)));
+      if (!role)
+	role = get_default_contract_role ();
+
+      contract_level level =
+	map_contract_level (IDENTIFIER_POINTER (TREE_VALUE (config)));
+      return contract_mode (level, role);
+    }
+
+  /* Literal semantic.  */
+  gcc_assert (TREE_CODE (config) == IDENTIFIER_NODE);
+  contract_semantic semantic =
+    map_contract_semantic (IDENTIFIER_POINTER (config));
+  return contract_mode (semantic);
+}
+
+/* Convert a contract's config into a concrete semantic using the current
+   contract semantic mapping.  */
+
+static contract_semantic
+compute_concrete_semantic (tree contract)
+{
+  contract_mode mode = contract_config_to_mode (CONTRACT_MODE (contract));
+  /* Compute the concrete semantic for the contract.  */
+  if (!flag_contract_mode)
+    /* If contracts are off, treat all contracts as ignore.  */
+    return CCS_IGNORE;
+  else if (mode.kind == contract_mode::cm_invalid)
+    return CCS_INVALID;
+  else if (mode.kind == contract_mode::cm_explicit)
+    return mode.get_semantic ();
+  else
+    {
+      gcc_assert (mode.get_role ());
+      gcc_assert (mode.get_level () != CONTRACT_INVALID);
+      contract_level level = mode.get_level ();
+      contract_role *role = mode.get_role ();
+      if (level == CONTRACT_DEFAULT)
+	return role->default_semantic;
+      else if (level == CONTRACT_AUDIT)
+	return role->audit_semantic;
+      else if (level == CONTRACT_AXIOM)
+	return role->axiom_semantic;
+    }
+  gcc_assert (false);
+}
+
+/* Return true if any contract in CONTRACT_ATTRs is not yet parsed.  */
+
+bool
+contract_any_deferred_p (tree contract_attr)
+{
+  for (; contract_attr; contract_attr = CONTRACT_CHAIN (contract_attr))
+    if (CONTRACT_CONDITION_DEFERRED_P (CONTRACT_STATEMENT (contract_attr)))
+      return true;
+  return false;
+}
+
+/* Returns true if all attributes are contracts.  */
+
+bool
+all_attributes_are_contracts_p (tree attributes)
+{
+  for (; attributes; attributes = TREE_CHAIN (attributes))
+    if (!cxx_contract_attribute_p (attributes))
+      return false;
+  return true;
+}
+
+/* Mark most of a contract as being invalid.  */
+
+tree
+invalidate_contract (tree t)
+{
+  if (TREE_CODE (t) == POSTCONDITION_STMT && POSTCONDITION_IDENTIFIER (t))
+    POSTCONDITION_IDENTIFIER (t) = error_mark_node;
+  CONTRACT_CONDITION (t) = error_mark_node;
+  CONTRACT_COMMENT (t) = error_mark_node;
+  return t;
+}
+
+/* Returns an invented parameter declration of the form 'TYPE ID' for the
+   purpose of parsing the postcondition.
+
+   We use a PARM_DECL instead of a VAR_DECL so that tsubst forces a lookup
+   in local specializations when we instantiate these things later.  */
+
+tree
+make_postcondition_variable (cp_expr id, tree type)
+{
+  if (id == error_mark_node)
+    return id;
+
+  tree decl = build_lang_decl (PARM_DECL, id, type);
+  DECL_ARTIFICIAL (decl) = true;
+  DECL_SOURCE_LOCATION (decl) = id.get_location ();
+
+  pushdecl (decl);
+  return decl;
+}
+
+/* As above, except that the type is unknown.  */
+
+tree
+make_postcondition_variable (cp_expr id)
+{
+  return make_postcondition_variable (id, make_auto ());
+}
+
+/* Check that the TYPE is valid for a named postcondition variable. Emit a
+   diagnostic if it is not.  Returns TRUE if the result is OK and false
+   otherwise.  */
+
+bool
+check_postcondition_result (tree decl, tree type, location_t loc)
+{
+  if (VOID_TYPE_P (type))
+  {
+    const char* what;
+    if (DECL_CONSTRUCTOR_P (decl))
+      what = "constructor";
+    else if (DECL_DESTRUCTOR_P (decl))
+      what  = "destructor";
+    else
+      what = "function";
+    error_at (loc, "%s does not return a value to test", what);
+    return false;
+  }
+
+  return true;
+}
+
+/* Instantiate each postcondition with the return type to finalize the
+   attribute.  */
+
+void
+rebuild_postconditions (tree decl, tree type)
+{
+  tree attributes = DECL_CONTRACTS (decl);
+
+  for (; attributes ; attributes = TREE_CHAIN (attributes))
+    {
+      if (!cxx_contract_attribute_p (attributes))
+	continue;
+      tree contract = TREE_VALUE (TREE_VALUE (attributes));
+      if (TREE_CODE (contract) != POSTCONDITION_STMT)
+	continue;
+      tree condition = CONTRACT_CONDITION (contract);
+
+      /* If any conditions are deferred, they're all deferred.  Note that
+	 we don't have to instantiate postconditions in that case because
+	 the type is available through the declaration.  */
+      if (TREE_CODE (condition) == DEFERRED_PARSE)
+	return;
+
+      tree oldvar = POSTCONDITION_IDENTIFIER (contract);
+      if (!oldvar)
+	continue;
+
+      /* Always update the context of the result variable so that it can
+	 be remapped by remap_contracts.  */
+      DECL_CONTEXT (oldvar) = decl;
+
+      /* If the return type is undeduced, defer until later.  */
+      if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+	return;
+
+      /* Check the postcondition variable.  */
+      location_t loc = DECL_SOURCE_LOCATION (oldvar);
+      if (!check_postcondition_result (decl, type, loc))
+	{
+	  invalidate_contract (contract);
+	  continue;
+	}
+
+      /* "Instantiate" the result variable using the known type.  Also update
+	  the context so the inliner will actually remap this the parameter when
+	  generating contract checks.  */
+      tree newvar = copy_node (oldvar);
+      TREE_TYPE (newvar) = type;
+
+      /* Make parameters and result available for substitution.  */
+      local_specialization_stack stack (lss_copy);
+      for (tree t = DECL_ARGUMENTS (decl); t != NULL_TREE; t = TREE_CHAIN (t))
+	register_local_identity (t);
+      register_local_specialization (newvar, oldvar);
+
+      ++processing_contract_condition;
+      condition = tsubst_expr (condition, make_tree_vec (0),
+			       tf_warning_or_error, decl, false);
+      --processing_contract_condition;
+
+      /* Update the contract condition and result.  */
+      POSTCONDITION_IDENTIFIER (contract) = newvar;
+      CONTRACT_CONDITION (contract) = finish_contract_condition (condition);
+    }
+}
+
+static tree
+build_comment (cp_expr condition)
+{
+  /* Try to get the actual source text for the condition; if that fails pretty
+     print the resulting tree.  */
+  char *str = get_source (condition.get_start (), condition.get_finish ());
+  if (!str)
+    {
+      /* FIXME cases where we end up here
+	 #line macro usage (oof)
+	 contracts10.C
+	 contracts11.C  */
+      const char *str = expr_to_string (condition);
+      return build_string_literal (strlen (str) + 1, str);
+    }
+
+  tree t = build_string_literal (strlen (str) + 1, str);
+  free (str);
+  return t;
+}
+
+/* Build a contract statement.  */
+
+tree
+grok_contract (tree attribute, tree mode, tree result, cp_expr condition,
+	       location_t loc)
+{
+  tree_code code;
+  if (is_attribute_p ("assert", attribute))
+    code = ASSERTION_STMT;
+  else if (is_attribute_p ("pre", attribute))
+    code = PRECONDITION_STMT;
+  else if (is_attribute_p ("post", attribute))
+    code = POSTCONDITION_STMT;
+  else
+    gcc_unreachable ();
+
+  /* Build the contract. The condition is added later.  In the case that
+     the contract is deferred, result an plain identifier, not a result
+     variable.  */
+  tree contract;
+  tree type = void_type_node;
+  if (code != POSTCONDITION_STMT)
+    contract = build3_loc (loc, code, type, mode, NULL_TREE, NULL_TREE);
+  else
+    contract = build4_loc (loc, code, type, mode, NULL_TREE, NULL_TREE, result);
+
+  /* Determine the concrete semantic.  */
+  set_contract_semantic (contract, compute_concrete_semantic (contract));
+
+  /* If the contract is deferred, don't do anything with the condition.  */
+  if (TREE_CODE (condition) == DEFERRED_PARSE)
+    {
+      CONTRACT_CONDITION (contract) = condition;
+      return contract;
+    }
+
+  /* Generate the comment from the original condition.  */
+  CONTRACT_COMMENT (contract) = build_comment (condition);
+
+  /* The condition is converted to bool.  */
+  condition = finish_contract_condition (condition);
+  CONTRACT_CONDITION (contract) = condition;
+
+  return contract;
+}
+
+/* Build the contract attribute specifier where IDENTIFIER is one of 'pre',
+   'post' or 'assert' and CONTRACT is the underlying statement.  */
+tree
+finish_contract_attribute (tree identifier, tree contract)
+{
+  if (contract == error_mark_node)
+    return error_mark_node;
+
+  tree attribute = build_tree_list (build_tree_list (NULL_TREE, identifier),
+				    build_tree_list (NULL_TREE, contract));
+
+
+  /* Mark the attribute as dependent if the condition is dependent.
+
+     TODO: I'm not sure this is strictly necessary. It's going to be marked as
+     such by a subroutine of cplus_decl_attributes. */
+  tree condition = CONTRACT_CONDITION (contract);
+  if (TREE_CODE (condition) == DEFERRED_PARSE
+      || value_dependent_expression_p (condition))
+    ATTR_IS_DEPENDENT (attribute) = true;
+
+  return attribute;
+}
+
+/* Update condition of a late-parsed contract and postcondition variable,
+   if any.  */
+
+void
+update_late_contract (tree contract, tree result, tree condition)
+{
+  if (TREE_CODE (contract) == POSTCONDITION_STMT)
+    POSTCONDITION_IDENTIFIER (contract) = result;
+
+  /* Generate the comment from the original condition.  */
+  CONTRACT_COMMENT (contract) = build_comment (condition);
+
+  /* The condition is converted to bool.  */
+  condition = finish_contract_condition (condition);
+  CONTRACT_CONDITION (contract) = condition;
+}
+
+/* Return TRUE iff ATTR has been parsed by the front-end as a c++2a contract
+   attribute. */
+
+bool
+cxx_contract_attribute_p (const_tree attr)
+{
+  if (attr == NULL_TREE
+      || TREE_CODE (attr) != TREE_LIST)
+    return false;
+
+  if (!TREE_PURPOSE (attr) || TREE_CODE (TREE_PURPOSE (attr)) != TREE_LIST)
+    return false;
+  if (!TREE_VALUE (attr) || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST)
+    return false;
+  if (!TREE_VALUE (TREE_VALUE (attr)))
+    return false;
+
+  return (TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == PRECONDITION_STMT
+      || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == POSTCONDITION_STMT
+      || TREE_CODE (TREE_VALUE (TREE_VALUE (attr))) == ASSERTION_STMT);
+}
+
+/* Remove all c++2a style contract attributes from the DECL_ATTRIBUTEs of the
+   FUNCTION_DECL FNDECL.  */
+
+void
+remove_contract_attributes (tree fndecl)
+{
+  tree list = NULL_TREE;
+  for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
+    if (!cxx_contract_attribute_p (p))
+      list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), NULL_TREE);
+  DECL_ATTRIBUTES (fndecl) = nreverse (list);
+}
+
+static tree find_first_non_contract (tree attributes)
+{
+  tree head = attributes;
+  tree p = find_contract (attributes);
+
+  /* There are no contracts.  */
+  if (!p)
+    return head;
+
+  /* There are leading contracts.  */
+  if (p == head)
+    {
+      while (cxx_contract_attribute_p (p))
+	p = TREE_CHAIN (p);
+      head = p;
+    }
+
+  return head;
+}
+
+/* Remove contracts from ATTRIBUTES.  */
+
+tree splice_out_contracts (tree attributes)
+{
+  tree head = find_first_non_contract (attributes);
+  if (!head)
+    return NULL_TREE;
+
+  /* Splice out remaining contracts.  */
+  tree p = TREE_CHAIN (head);
+  tree q = head;
+  while (p)
+    {
+      if (cxx_contract_attribute_p (p))
+	{
+	  /* Skip a sequence of contracts and then link q to the next
+	     non-contract attribute.  */
+	  do
+	    p = TREE_CHAIN (p);
+	  while (cxx_contract_attribute_p (p));
+	  TREE_CHAIN (q) = p;
+	}
+      else
+	p = TREE_CHAIN (p);
+    }
+
+  return head;
+}
+
+/* Copy contract attributes from NEWDECL onto the attribute list of OLDDECL.  */
+
+void copy_contract_attributes (tree newdecl, tree olddecl)
+{
+  tree attrs = NULL_TREE;
+  for (tree c = DECL_CONTRACTS (olddecl); c; c = TREE_CHAIN (c))
+    {
+      if (!cxx_contract_attribute_p (c))
+	continue;
+      attrs = tree_cons (TREE_PURPOSE (c), TREE_VALUE (c), attrs);
+    }
+  attrs = chainon (DECL_ATTRIBUTES (newdecl), nreverse (attrs));
+  DECL_ATTRIBUTES (newdecl) = attrs;
+}
+
+/* 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
+get_postcondition_result_parameter (tree d)
+{
+  if (!d || d == error_mark_node)
+    return NULL_TREE;
+
+  if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (d))))
+    return NULL_TREE;
+
+  tree post = DECL_POST_FN (d);
+  if (!post || post == error_mark_node)
+    return NULL_TREE;
+
+  for (tree arg = DECL_ARGUMENTS (post); arg; arg = TREE_CHAIN (arg))
+    if (!TREE_CHAIN (arg))
+      return arg;
+
+  return NULL_TREE;
+}
+
+
+/* For use with the tree inliner. This preserves non-mapped local variables,
+   such as postcondition result variables, during remapping.  */
+
+static tree
+retain_decl (tree decl, copy_body_data *)
+{
+  return decl;
+}
+
+/* Rewrite the condition of contract in place, so that references to SRC's
+   parameters are updated to refer to DST's parameters. The postcondition
+   result variable is left unchanged.
+
+   This, along with remap_contracts, are subroutines of duplicate_decls.
+   When declarations are merged, we sometimes need to update contracts to
+   refer to new parameters.
+
+   If DUPLICATE_P is true, this is called by duplicate_decls to rewrite contacts
+   in terms of a new set of parameters. In this case, we can retain local
+   variables appearing in the contract because the contract is not being
+   prepared for insertion into a new function. Importantly, this preserves the
+   references to postcondition results, which are not replaced during merging.
+
+   If false, we're preparing to emit the contract condition into the body
+   of a new function, so we need to make copies of all local variables
+   appearing in the contract (e.g., if it includes a lambda expression). Note
+   that in this case, postcondition results are mapped to the last parameter
+   of DST.
+
+   This is also used to reuse a parent type's contracts on virtual methods.  */
+
+void
+remap_contract (tree src, tree dst, tree contract, bool duplicate_p)
+{
+  copy_body_data id;
+  hash_map<tree, tree> decl_map;
+
+  memset (&id, 0, sizeof (id));
+  id.src_fn = src;
+  id.dst_fn = dst;
+  id.src_cfun = DECL_STRUCT_FUNCTION (src);
+  id.decl_map = &decl_map;
+
+  /* If we're merging contracts, don't copy local variables.  */
+  id.copy_decl = duplicate_p ? retain_decl : copy_decl_no_change;
+
+  id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+  id.transform_new_cfg = false;
+  id.transform_return_to_modify = false;
+  id.transform_parameter = true;
+  id.transform_lang_insert_block = NULL;
+
+  /* Make sure not to unshare trees behind the front-end's back
+     since front-end specific mechanisms may rely on sharing.  */
+  id.regimplify = false;
+  id.do_not_unshare = true;
+  id.do_not_fold = true;
+
+  /* We're not inside any EH region.  */
+  id.eh_lp_nr = 0;
+
+  bool do_remap = false;
+
+  /* Insert parameter remappings.  */
+  if (TREE_CODE (src) == FUNCTION_DECL)
+    src = DECL_ARGUMENTS (src);
+  if (TREE_CODE (dst) == FUNCTION_DECL)
+    dst = DECL_ARGUMENTS (dst);
+
+  for (tree sp = src, dp = dst;
+       sp || dp;
+       sp = DECL_CHAIN (sp), dp = DECL_CHAIN (dp))
+    {
+      if (!sp && dp
+	  && TREE_CODE (contract) == POSTCONDITION_STMT
+	  && DECL_CHAIN (dp) == NULL_TREE)
+	{
+	  gcc_assert (!duplicate_p);
+	  if (tree result = POSTCONDITION_IDENTIFIER (contract))
+	    {
+	      gcc_assert (DECL_P (result));
+	      insert_decl_map (&id, result, dp);
+	      do_remap = true;
+	    }
+	  break;
+	}
+      gcc_assert (sp && dp);
+
+      if (sp == dp)
+	continue;
+
+      insert_decl_map (&id, sp, dp);
+      do_remap = true;
+    }
+  if (!do_remap)
+    return;
+
+  walk_tree (&CONTRACT_CONDITION (contract), copy_tree_body_r, &id, NULL);
+}
+
+/* Rewrite any references to SRC's PARM_DECLs to the corresponding PARM_DECL in
+   DST in all of the contract attributes in CONTRACTS by calling remap_contract
+   on each.
+
+   This is used for two purposes: to rewrite contract attributes during
+   duplicate_decls, and to prepare contracts for emission into a function's
+   respective precondition and postcondition functions. DUPLICATE_P is used
+   to determine the context in which this function is called. See above for
+   the behavior described by this flag.  */
+
+void
+remap_contracts (tree src, tree dst, tree contracts, bool duplicate_p)
+{
+  for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
+    {
+      if (!cxx_contract_attribute_p (attr))
+	continue;
+      tree contract = CONTRACT_STATEMENT (attr);
+      if (TREE_CODE (CONTRACT_CONDITION (contract)) != DEFERRED_PARSE)
+	remap_contract (src, dst, contract, duplicate_p);
+    }
+}
+
+/* Helper to replace references to dummy this parameters with references to
+   the first argument of the FUNCTION_DECL DATA.  */
+
+static tree
+remap_dummy_this_1 (tree *tp, int *, void *data)
+{
+  if (!is_this_parameter (*tp))
+    return NULL_TREE;
+  tree fn = (tree)data;
+  *tp = DECL_ARGUMENTS (fn);
+  return NULL_TREE;
+}
+
+/* Replace all references to dummy this parameters in EXPR with references to
+   the first argument of the FUNCTION_DECL FN.  */
+
+void
+remap_dummy_this (tree fn, tree *expr)
+{
+  walk_tree (expr, remap_dummy_this_1, fn, NULL);
+}
+
+/* Contract matching.  */
+
+/* True if the contract is valid.  */
+
+static bool
+contract_valid_p (tree contract)
+{
+  return CONTRACT_CONDITION (contract) != error_mark_node;
+}
+
+/* True if the contract attribute is valid.  */
+
+static bool
+contract_attribute_valid_p (tree attribute)
+{
+  return contract_valid_p (TREE_VALUE (TREE_VALUE (attribute)));
+}
+
+/* Compare the contract conditions of OLD_ATTR and NEW_ATTR. Returns false
+   if the conditions are equivalent, and true otherwise.  */
+
+static bool
+check_for_mismatched_contracts (tree old_attr, tree new_attr,
+			       contract_matching_context ctx)
+{
+  tree old_contract = CONTRACT_STATEMENT (old_attr);
+  tree new_contract = CONTRACT_STATEMENT (new_attr);
+
+  /* Different kinds of contracts do not match.  */
+  if (TREE_CODE (old_contract) != TREE_CODE (new_contract))
+    {
+      auto_diagnostic_group d;
+      error_at (EXPR_LOCATION (new_contract),
+		ctx == cmc_declaration
+		? "mismatched contract attribute in declaration"
+		: "mismatched contract attribute in override");
+      inform (EXPR_LOCATION (old_contract), "previous contract here");
+      return true;
+    }
+
+  /* Two deferred contracts tentatively match.  */
+  if (CONTRACT_CONDITION_DEFERRED_P  (old_contract)
+      && CONTRACT_CONDITION_DEFERRED_P (new_contract))
+    return false;
+
+  /* Compare the conditions of the contracts.  We fold immediately to avoid
+     issues comparing contracts on overrides that use parameters -- see
+     contracts-pre3.  */
+  tree t1 = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
+  tree t2 = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
+
+  /* Compare the contracts. The fold doesn't eliminate conversions to members.
+     Set the comparing_override_contracts flag to ensure that references
+     through 'this' are equal if they designate the same member, regardless of
+     the path those members.  */
+  bool saved_comparing_contracts = comparing_override_contracts;
+  comparing_override_contracts = (ctx == cmc_override);
+  bool matching_p = cp_tree_equal (t1, t2);
+  comparing_override_contracts = saved_comparing_contracts;
+
+  if (!matching_p)
+    {
+      auto_diagnostic_group d;
+      error_at (EXPR_LOCATION (CONTRACT_CONDITION (new_contract)),
+		ctx == cmc_declaration
+		? "mismatched contract condition in declaration"
+		: "mismatched contract condition in override");
+      inform (EXPR_LOCATION (CONTRACT_CONDITION (old_contract)),
+	      "previous contract here");
+      return true;
+    }
+
+  return false;
+}
+
+/* Compare the contract attributes of OLDDECL and NEWDECL. Returns true
+   if the contracts match, and false if they differ.  */
+
+bool
+match_contract_conditions (location_t oldloc, tree old_attrs,
+			   location_t newloc, tree new_attrs,
+			   contract_matching_context ctx)
+{
+  /* Contracts only match if they are both specified.  */
+  if (!old_attrs || !new_attrs)
+    return true;
+
+  /* Compare each contract in turn.  */
+  while (old_attrs && new_attrs)
+    {
+      /* If either contract is ill-formed, skip the rest of the comparison,
+	 since we've already diagnosed an error.  */
+      if (!contract_attribute_valid_p (new_attrs)
+	  || !contract_attribute_valid_p (old_attrs))
+	return false;
+
+      if (check_for_mismatched_contracts (old_attrs, new_attrs, ctx))
+	return false;
+      old_attrs = CONTRACT_CHAIN (old_attrs);
+      new_attrs = CONTRACT_CHAIN (new_attrs);
+    }
+
+  /* If we didn't compare all attributes, the contracts don't match.  */
+  if (old_attrs || new_attrs)
+    {
+      auto_diagnostic_group d;
+      error_at (newloc,
+		ctx == cmc_declaration
+		? "declaration has a different number of contracts than "
+		  "previously declared"
+		: "override has a different number of contracts than "
+		  "previously declared");
+      inform (oldloc,
+	      new_attrs
+	      ? "original declaration with fewer contracts here"
+	      : "original declaration with more contracts here");
+      return false;
+    }
+
+  return true;
+}
+
+/* Deferred contract mapping.
+
+   This is used to compare late-parsed contracts on overrides with their
+   base class functions.
+
+   TODO: It seems like this could be replaced by a simple list that maps from
+   overrides to their base functions. It's not clear that we really need
+   a map to a function + a list of contracts.   */
+
+/* Map from FNDECL to a tree list of contracts that have not been matched or
+   diagnosed yet.  The TREE_PURPOSE is the basefn we're overriding, and the
+   TREE_VALUE is the list of contract attrs for BASEFN.  */
+
+static hash_map<tree_decl_hash, tree> pending_guarded_decls;
+
+void
+defer_guarded_contract_match (tree fndecl, tree fn, tree contracts)
+{
+  if (!pending_guarded_decls.get (fndecl))
+    {
+      pending_guarded_decls.put (fndecl, build_tree_list (fn, contracts));
+      return;
+    }
+  for (tree pending = *pending_guarded_decls.get (fndecl);
+      pending;
+      pending = TREE_CHAIN (pending))
+    {
+      if (TREE_VALUE (pending) == contracts)
+	return;
+      if (TREE_CHAIN (pending) == NULL_TREE)
+	TREE_CHAIN (pending) = build_tree_list (fn, contracts);
+    }
+}
+
+/* If the FUNCTION_DECL DECL has any contracts that had their matching
+   deferred earlier, do that checking now.  */
+
+void
+match_deferred_contracts (tree decl)
+{
+  tree *tp = pending_guarded_decls.get (decl);
+  if (!tp)
+    return;
+
+  gcc_assert(!contract_any_deferred_p (DECL_CONTRACTS (decl)));
+
+  /* Do late contract matching.  */
+  for (tree pending = *tp; pending; pending = TREE_CHAIN (pending))
+    {
+      tree new_contracts = TREE_VALUE (pending);
+      location_t new_loc = CONTRACT_SOURCE_LOCATION (new_contracts);
+      tree old_contracts = DECL_CONTRACTS (decl);
+      location_t old_loc = CONTRACT_SOURCE_LOCATION (old_contracts);
+      tree base = TREE_PURPOSE (pending);
+      match_contract_conditions (new_loc, new_contracts,
+				 old_loc, old_contracts,
+				 base ? cmc_override : cmc_declaration);
+    }
+
+  /* Clear out deferred match list so we don't check it twice.  */
+  pending_guarded_decls.remove (decl);
+}
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 00b7772fe0d..2c15b39b2ed 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1194,6 +1194,30 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
       wtd->bind_expr_stack.pop ();
       break;
 
+    case ASSERTION_STMT:
+    case PRECONDITION_STMT:
+    case POSTCONDITION_STMT:
+      {
+	if (tree check = build_contract_check (stmt))
+	  {
+	//     verbatim ("MAKE CHECK");
+	//     debug_expression (check);
+	    /* Mark the current function as possibly throwing exceptions
+	       (through invocation of the contract violation handler).  */
+	    current_function_returns_abnormally = 1;
+	    TREE_NOTHROW (current_function_decl) = 0;
+
+	    *stmt_p = check;
+	    return cp_genericize_r (stmt_p, walk_subtrees, data);
+	  }
+
+	/* If we didn't build a check, replace it with void_node so we don't
+	   leak contracts into GENERIC.  */
+	*stmt_p = void_node;
+	*walk_subtrees = 0;
+      }
+      break;
+
     case USING_STMT:
       {
 	tree block = NULL_TREE;
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 46b2248574c..4ec99f14c74 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cp-objcp-common.h"
 #include "dwarf2.h"
 #include "stringpool.h"
+#include "contracts.h"
 
 /* Special routine to get the alias set for C++.  */
 
@@ -83,6 +84,9 @@ cp_tree_size (enum tree_code code)
     case CONSTRAINT_INFO:       return sizeof (tree_constraint_info);
     case USERDEF_LITERAL:	return sizeof (tree_userdef_literal);
     case TEMPLATE_DECL:		return sizeof (tree_template_decl);
+    case ASSERTION_STMT:	return sizeof (tree_exp);
+    case PRECONDITION_STMT:	return sizeof (tree_exp);
+    case POSTCONDITION_STMT:	return sizeof (tree_exp);
     default:
       switch (TREE_CODE_CLASS (code))
 	{
@@ -552,6 +556,10 @@ cp_common_init_ts (void)
   MARK_TS_EXP (CO_YIELD_EXPR);
   MARK_TS_EXP (CO_RETURN_EXPR);
 
+  MARK_TS_EXP (ASSERTION_STMT);
+  MARK_TS_EXP (PRECONDITION_STMT);
+  MARK_TS_EXP (POSTCONDITION_STMT);
+
   c_common_init_ts ();
 }
 
@@ -564,6 +572,39 @@ cp_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 {
   if (handle_module_option (unsigned (scode), arg, value))
     return true;
+
+  enum opt_code code = (enum opt_code) scode;
+  bool handled_p = true;
+
+  switch (code)
+    {
+    case OPT_fcontract_build_level_:
+      handle_OPT_fcontract_build_level_ (arg);
+      break;
+
+    case OPT_fcontract_assumption_mode_:
+      handle_OPT_fcontract_assumption_mode_ (arg);
+      break;
+
+    case OPT_fcontract_continuation_mode_:
+      handle_OPT_fcontract_continuation_mode_ (arg);
+      break;
+
+    case OPT_fcontract_role_:
+      handle_OPT_fcontract_role_ (arg);
+      break;
+
+    case OPT_fcontract_semantic_:
+      handle_OPT_fcontract_semantic_ (arg);
+      break;
+
+    default:
+      handled_p = false;
+      break;
+    }
+  if (handled_p)
+    return handled_p;
+
   return c_common_handle_option (scode, arg, value, kind, loc, handlers);
 }
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3a5a2c64b24..1b17dfc2419 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -103,6 +103,7 @@ static void store_parm_decls (tree);
 static void initialize_local_var (tree, tree);
 static void expand_static_init (tree, tree);
 static location_t smallest_type_location (const cp_decl_specifier_seq*);
+static void finish_function_contracts (tree fndecl);
 
 /* The following symbols are subsumed in the cp_global_trees array, and
    listed here individually for documentation purposes.
@@ -946,6 +947,28 @@ determine_local_discriminator (tree decl)
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
 }
 
+/* Called on attribute lists that must not contain contracts.  If any
+   contracts are present, issue an error diagnostic and return true.  */
+
+bool
+diagnose_misapplied_contracts (tree attributes)
+{
+  if (attributes == NULL_TREE)
+    return false;
+
+  tree contract_attr = find_contract (attributes);
+  if (!contract_attr)
+    return false;
+
+  error_at (EXPR_LOCATION (CONTRACT_STATEMENT (contract_attr)),
+	    "contracts must appertain to a function type");
+
+  /* Invalidate the contract so we don't treat it as valid later on.  */
+  invalidate_contract (TREE_VALUE (TREE_VALUE (contract_attr)));
+
+  return true;
+}
+
 \f
 
 /* Returns true if functions FN1 and FN2 have equivalent trailing
@@ -1463,6 +1486,118 @@ duplicate_function_template_decls (tree newdecl, tree olddecl)
   return false;
 }
 
+/* This temporarily contains the attribute list for a friend declaration in
+   grokdecl. Friend declarations are merged together before attributes are
+   processed, which complicates the processing of contracts. In particular, we
+   need to compare and possibly remap contracts in duplicate_decls.  */
+
+static tree friend_attributes;
+
+/* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
+   guarded functions.  Note that attributes on new friend declarations have not
+   been processed yet, so we take those from the global above.  */
+
+static void
+duplicate_contracts (tree newdecl, tree olddecl)
+{
+  /* Compare contracts to see if they match.    */
+  tree old_contracts = DECL_CONTRACTS (olddecl);
+  tree new_contracts;
+  if (friend_attributes)
+    new_contracts = friend_attributes;
+  else
+    new_contracts = DECL_CONTRACTS (newdecl);
+
+  if (!old_contracts && !new_contracts)
+    return;
+
+  location_t old_loc = DECL_SOURCE_LOCATION (olddecl);
+  location_t new_loc = DECL_SOURCE_LOCATION (newdecl);
+
+  /* If both declarations specify contracts, ensure they match.
+
+     TODO: This handles a potential error a little oddly. Consider:
+
+	struct B {
+	  virtual void f(int n) [[pre: n == 0]];
+	};
+	struct D : B {
+	  void f(int n) override; // inherits contracts
+	};
+	void D::f(int n) [[pre: n == 0]] // OK
+	{ }
+
+    It's okay because we're explicitly restating the inherited contract.
+    Changing the precondition on the definition D::f causes match_contracts
+    to complain about the mismatch.
+
+    This would previously have been diagnosed as adding contracts to an
+    override, but this seems like it should be well-formed.  */
+  if (old_contracts && new_contracts)
+    {
+      if (!match_contract_conditions (old_loc, old_contracts,
+				      new_loc, new_contracts,
+				      cmc_declaration))
+	return;
+    }
+
+  /* Handle cases where contracts are omitted in one or the other
+     declaration.  */
+  if (old_contracts)
+    {
+      /* Contracts have been previously specified by are no omitted. The
+	 new declaration inherits the existing contracts. */
+      if (!new_contracts)
+	copy_contract_attributes (newdecl, olddecl);
+
+      /* In all cases, remove existing contracts from OLDDECL to prevent the
+	 attribute merging function from adding excess contracts.  */
+      remove_contract_attributes (olddecl);
+    }
+  else if (!old_contracts)
+    {
+      /* We are adding contracts to a declaration.  */
+      if (new_contracts)
+	{
+	  /* We can't add to a previously defined function.  */
+	  if (DECL_INITIAL (olddecl))
+	    {
+	      auto_diagnostic_group d;
+	      error_at (new_loc, "cannot add contracts after definition");
+	      inform (DECL_SOURCE_LOCATION (olddecl), "original definition here");
+	      return;
+	    }
+
+	  /* We can't add to an unguarded virtual function declaration.  */
+	  if (DECL_VIRTUAL_P (olddecl) && new_contracts)
+	    {
+	      auto_diagnostic_group d;
+	      error_at (new_loc, "cannot add contracts to a virtual function");
+	      inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here");
+	      return;
+	    }
+
+	  /* Depending on the "first declaration" rule, we may not be able
+	     to add contracts to a function after the fact.  */
+	  if (flag_contract_strict_declarations)
+	    {
+	      warning_at (new_loc,
+			  OPT_fcontract_strict_declarations_,
+			  "declaration adds contracts to %q#D",
+			  olddecl);
+	      return;
+	    }
+
+	  /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to
+	     remap them because NEWDECL's parameters will replace those of
+	     OLDDECL.  Remove the contracts from NEWDECL so they aren't
+	     cloned when merging.  */
+	  copy_contract_attributes (olddecl, newdecl);
+	  remove_contract_attributes (newdecl);
+	}
+    }
+}
+
 /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
    If the redeclaration is invalid, a diagnostic is issued, and the
    error_mark_node is returned.  Otherwise, OLDDECL is returned.
@@ -2138,6 +2273,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	  = DECL_OVERLOADED_OPERATOR_CODE_RAW (olddecl);
       new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE;
 
+      duplicate_contracts (newdecl, olddecl);
+
       /* Optionally warn about more than one declaration for the same
 	 name, but don't warn about a function declaration followed by a
 	 definition.  */
@@ -2211,6 +2348,26 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	 specializations.  */
       gcc_assert (!DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
 
+      /* Make sure the contracts are equivalent.  */
+      tree old_contracts = DECL_CONTRACTS (old_result);
+      tree new_contracts = friend_attributes
+	? find_contract (friend_attributes)
+	: DECL_CONTRACTS (new_result);
+      if (DECL_CONTRACTS (old_result) && new_contracts)
+	{
+	  match_contract_conditions (DECL_SOURCE_LOCATION (old_result),
+				     old_contracts,
+				     DECL_SOURCE_LOCATION (new_result),
+				     new_contracts,
+				     cmc_declaration);
+	}
+
+      /* Remove contracts from old_result so they aren't appended to
+	 old_result by the merge function.  If we're duplicating because
+	 NEWDECL is a friend, do not do this!  */
+      if (!friend_attributes)
+	remove_contract_attributes (old_result);
+
       DECL_ATTRIBUTES (old_result)
 	= (*targetm.merge_decl_attributes) (old_result, new_result);
 
@@ -2274,12 +2431,30 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	  DECL_INITIAL (old_result) = DECL_INITIAL (new_result);
 	  if (DECL_FUNCTION_TEMPLATE_P (newdecl))
 	    {
-	      tree parm;
-	      DECL_ARGUMENTS (old_result)
-		= DECL_ARGUMENTS (new_result);
-	      for (parm = DECL_ARGUMENTS (old_result); parm;
-		   parm = DECL_CHAIN (parm))
-		DECL_CONTEXT (parm) = old_result;
+	      DECL_ARGUMENTS (old_result) = DECL_ARGUMENTS (new_result);
+	      for (tree p = DECL_ARGUMENTS (old_result); p; p = DECL_CHAIN (p))
+		DECL_CONTEXT (p) = old_result;
+	    }
+
+	  /* In general, contracts are re-mapped to their parameters when
+	     instantiated. However, for friends, we need to update the
+	     previous declaration here.
+
+	     TODO: It would be nice if we could avoid doing this here.  */
+	  if (friend_attributes)
+	    {
+	      remove_contract_attributes (old_result);
+	      tree list = NULL_TREE;
+	      for (tree p = new_contracts; p; p = TREE_CHAIN (p))
+		{
+		  if (cxx_contract_attribute_p (p))
+		    list = tree_cons (TREE_PURPOSE (p),
+				      TREE_VALUE (p),
+				      NULL_TREE);
+		}
+	      nreverse (list);
+	      DECL_ATTRIBUTES (old_result)
+		= chainon (DECL_ATTRIBUTES (old_result), list);
 	    }
 	}
 
@@ -2712,11 +2887,23 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	}
       if (! types_match || new_defines_function)
 	{
+	  /* These are the final DECL_ARGUMENTS that will be used within the
+	     body; update any references to old DECL_ARGUMENTS in the
+	     contracts, if present.  */
+	  if (tree contracts = DECL_CONTRACTS (newdecl))
+	    remap_contracts (olddecl, newdecl, contracts, true);
+
 	  /* These need to be copied so that the names are available.
 	     Note that if the types do match, we'll preserve inline
 	     info and other bits, but if not, we won't.  */
 	  DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
 	  DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
+
+	  /* In some cases, duplicate_contracts will remove contracts from
+	     OLDDECL, to avoid duplications. Sometimes, the contracts end up
+	     shared. If we removed them, re-add them.  */
+	  if (!DECL_CONTRACTS (olddecl))
+	    copy_contract_attributes (olddecl, newdecl);
 	}
       /* If redeclaring a builtin function, it stays built in
 	 if newdecl is a gnu_inline definition, or if newdecl is just
@@ -2760,7 +2947,36 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	  /* Don't clear out the arguments if we're just redeclaring a
 	     function.  */
 	  if (DECL_ARGUMENTS (olddecl))
-	    DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+	    {
+	      /* If we removed contracts from previous definition, re-attach
+		 them. Otherwise, rewrite the contracts so they match the
+		 parameters of the new declaration.  */
+	      if (DECL_INITIAL (olddecl)
+		  && DECL_CONTRACTS (newdecl)
+		  && !DECL_CONTRACTS (olddecl))
+		    copy_contract_attributes (olddecl, newdecl);
+	      else {
+	      /* Temporarily undo the re-contexting of parameters so we
+		 can actually remap parameters.  The inliner won't replace
+		 parameters if we don't do this.  */
+	      tree args = DECL_ARGUMENTS (newdecl);
+	      for (tree p = args; p; p = DECL_CHAIN (p))
+		DECL_CONTEXT (p) = newdecl;
+
+	      /* Save new argument names for use in contracts parsing, unless
+		 we've already started parsing the body of olddecl (particular
+		 issues arise when newdecl is from a prior friend decl with no
+		 argument names, see modules/contracts-tpl-friend-1).  */
+	      if (tree contracts = DECL_CONTRACTS (olddecl))
+		remap_contracts (newdecl, olddecl, contracts, true);
+
+	      /* And reverse this operation again. */
+	      for (tree p = args; p; p = DECL_CHAIN (p))
+		DECL_CONTEXT (p) = olddecl;
+	      }
+
+	      DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+	    }
 	}
     }
   else if (TREE_CODE (newdecl) == NAMESPACE_DECL)
@@ -5303,6 +5519,12 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
 	warn_misplaced_attr_for_class_type (loc, declared_type);
     }
 
+  /* Diagnose invalid application of contracts, if any.  */
+  if (find_contract (declspecs->attributes))
+    diagnose_misapplied_contracts (declspecs->attributes);
+  else
+    diagnose_misapplied_contracts (declspecs->std_attributes);
+
   return declared_type;
 }
 
@@ -5591,9 +5813,16 @@ start_decl (const cp_declarator *declarator,
       if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
 	  /* Aliases are definitions. */
 	  && !alias)
-	permerror (declarator->id_loc,
-		   "declaration of %q#D outside of class is not definition",
-		   decl);
+	{
+	  if (DECL_VIRTUAL_P (decl) || !flag_contracts)
+	    permerror (declarator->id_loc,
+		       "declaration of %q#D outside of class is not definition",
+		       decl);
+	  else if (flag_contract_strict_declarations)
+	    warning_at (declarator->id_loc, OPT_fcontract_strict_declarations_,
+			"declaration of %q#D outside of class is not definition",
+			decl);
+	}
     }
 
   /* Create a DECL_LANG_SPECIFIC so that DECL_DECOMPOSITION_P works.  */
@@ -10178,6 +10407,9 @@ grokfndecl (tree ctype,
       *attrlist = NULL_TREE;
     }
 
+  if (DECL_HAS_CONTRACTS_P (decl))
+    rebuild_postconditions (decl, TREE_TYPE (type));
+
   /* Check main's type after attributes have been applied.  */
   if (ctype == NULL_TREE && DECL_MAIN_P (decl))
     {
@@ -12318,7 +12550,8 @@ grokdeclarator (const cp_declarator *declarator,
 	}
     }
 
-  if (declspecs->std_attributes)
+  if (declspecs->std_attributes
+      && !diagnose_misapplied_contracts (declspecs->std_attributes))
     {
       location_t attr_loc = declspecs->locations[ds_std_attribute];
       if (warning_at (attr_loc, OPT_Wattributes, "attribute ignored"))
@@ -12326,6 +12559,9 @@ grokdeclarator (const cp_declarator *declarator,
 		"is ignored");
     }
 
+  if (attrlist)
+    diagnose_misapplied_contracts (*attrlist);
+
   /* Determine the type of the entity declared by recurring on the
      declarator.  */
   for (; declarator; declarator = declarator->declarator)
@@ -12362,6 +12598,11 @@ grokdeclarator (const cp_declarator *declarator,
 
       inner_declarator = declarator->declarator;
 
+      /* Check that contracts aren't misapplied.  */
+      tree contract_attr = find_contract (declarator->std_attributes);
+      if (contract_attr && !function_declarator_p (declarator))
+	diagnose_misapplied_contracts (contract_attr);
+
       /* We don't want to warn in parameter context because we don't
 	 yet know if the parse will succeed, and this might turn out
 	 to be a constructor call.  */
@@ -12766,6 +13007,24 @@ grokdeclarator (const cp_declarator *declarator,
 		else
 		  returned_attrs = chainon (returned_attrs, att);
 	      }
+
+	    /* Contract attributes appertain to the declaration.  */
+	    tree *p;
+	    for (p = &attrs; *p;)
+	      {
+		tree l = *p;
+		if (cxx_contract_attribute_p (l))
+		  {
+		    *p = TREE_CHAIN (l);
+		    /* Intentially reverse order of contracts so they're
+		       reversed back into their lexical order.  */
+		    TREE_CHAIN (l) = NULL_TREE;
+		    returned_attrs = chainon (l, returned_attrs);
+		  }
+		else
+		  p = &TREE_CHAIN (l);
+	     }
+
 	    if (attrs)
 	      /* [dcl.fct]/2:
 
@@ -13776,7 +14035,10 @@ grokdeclarator (const cp_declarator *declarator,
 	  {
 	    /* Packages tend to use GNU attributes on friends, so we only
 	       warn for standard attributes.  */
-	    if (attrlist && !funcdef_flag && cxx11_attribute_p (*attrlist))
+	    if (attrlist
+		&& !funcdef_flag
+		&& cxx11_attribute_p (*attrlist)
+		&& !all_attributes_are_contracts_p (*attrlist))
 	      {
 		*attrlist = NULL_TREE;
 		if (warning_at (id_loc, OPT_Wattributes, "attribute ignored"))
@@ -13805,9 +14067,9 @@ grokdeclarator (const cp_declarator *declarator,
 		      return error_mark_node;
 		  }
 
-		decl = do_friend (ctype, unqualified_id, decl,
+		auto fao = make_temp_override(friend_attributes, *attrlist);
+		return do_friend (ctype, unqualified_id, decl,
 				  flags, funcdef_flag);
-		return decl;
 	      }
 	    else
 	      return error_mark_node;
@@ -16879,9 +17141,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
 
   ++function_depth;
 
-  if (DECL_DESTRUCTOR_P (decl1)
-      || (DECL_CONSTRUCTOR_P (decl1)
-	  && targetm.cxx.cdtor_returns_this ()))
+  if (DECL_CDTOR_NEEDS_LABLED_EXIT_P (decl1))
     {
       cdtor_label = create_artificial_label (input_location);
       LABEL_DECL_CDTOR (cdtor_label) = true;
@@ -16893,6 +17153,35 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
 
   push_operator_bindings ();
 
+  bool starting_guarded_p = !processing_template_decl
+      && DECL_ORIGINAL_FN (decl1) == NULL_TREE
+      && contract_any_active_p (DECL_CONTRACTS (decl1))
+      && !DECL_CONSTRUCTOR_P (decl1)
+      && !DECL_DESTRUCTOR_P (decl1);
+  /* Contracts may have just been added without a chance to parse them, though
+     we still need the PRE_FN available to generate a call to it.  */
+  if (starting_guarded_p && !DECL_PRE_FN (decl1))
+    build_contract_function_decls (decl1);
+
+  /* If we're starting a guarded function with valid contracts, we need to
+     insert a call to the pre function.  */
+  if (starting_guarded_p && DECL_PRE_FN (decl1)
+      && DECL_PRE_FN (decl1) != error_mark_node)
+    {
+      vec<tree, va_gc> *args = build_arg_list (decl1);
+
+      push_deferring_access_checks (dk_no_check);
+      tree call = finish_call_expr (DECL_PRE_FN (decl1), &args,
+				    /*disallow_virtual=*/true,
+				    /*koenig_p=*/false,
+				    /*complain=*/tf_warning_or_error);
+      gcc_assert (call != error_mark_node);
+      pop_deferring_access_checks ();
+
+      /* Just add the call expression.  */
+      finish_expr_stmt (call);
+    }
+
   if (!processing_template_decl
       && (flag_lifetime_dse > 1)
       && DECL_CONSTRUCTOR_P (decl1)
@@ -17057,11 +17346,14 @@ finish_constructor_body (void)
   tree val;
   tree exprstmt;
 
+  /* Any return from a constructor will end up here.  */
+  if (DECL_CDTOR_NEEDS_LABLED_EXIT_P (current_function_decl))
+    add_stmt (build_stmt (input_location, LABEL_EXPR, cdtor_label));
+
+  emit_postconditions (DECL_CONTRACTS (current_function_decl));
+
   if (targetm.cxx.cdtor_returns_this ())
     {
-      /* Any return from a constructor will end up here.  */
-      add_stmt (build_stmt (input_location, LABEL_EXPR, cdtor_label));
-
       val = DECL_ARGUMENTS (current_function_decl);
       val = build2 (MODIFY_EXPR, TREE_TYPE (val),
 		    DECL_RESULT (current_function_decl), val);
@@ -17137,6 +17429,8 @@ begin_destructor_body (void)
 	 will be properly destroyed if we throw.  */
       push_base_cleanups ();
     }
+
+  emit_preconditions (DECL_CONTRACTS (current_function_decl));
 }
 
 /* At the end of every destructor we generate code to delete the object if
@@ -17151,6 +17445,8 @@ finish_destructor_body (void)
      and member cleanups will be run when the function returns.  */
   add_stmt (build_stmt (input_location, LABEL_EXPR, cdtor_label));
 
+  emit_postconditions (DECL_CONTRACTS (current_function_decl));
+
   if (targetm.cxx.cdtor_returns_this ())
     {
       tree val;
@@ -17374,6 +17670,13 @@ finish_function (bool inline_p)
 			      current_eh_spec_block);
     }
 
+  /* True if this is a guarded function.  */
+  bool finishing_guarded_p = !processing_template_decl
+    && DECL_ORIGINAL_FN (fndecl) == NULL_TREE
+    && contract_any_active_p (DECL_CONTRACTS (fndecl))
+    && !DECL_CONSTRUCTOR_P (fndecl)
+    && !DECL_DESTRUCTOR_P (fndecl);
+
   /* If we're saving up tree structure, tie off the function now.  */
   DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
 
@@ -17641,8 +17944,75 @@ finish_function (bool inline_p)
   current_function_decl = NULL_TREE;
 
   invoke_plugin_callbacks (PLUGIN_FINISH_PARSE_FUNCTION, fndecl);
+
+  if (finishing_guarded_p)
+    finish_function_contracts (fndecl);
+
   return fndecl;
 }
+
+/* Finish up the pre & post function definitions for a guarded FNDECL,
+   and compile those functions all the way to assembler language output.  */
+
+static void
+finish_function_contracts (tree fndecl)
+{
+  for (tree ca = DECL_CONTRACTS (fndecl); ca; ca = CONTRACT_CHAIN (ca))
+    {
+      tree contract = CONTRACT_STATEMENT (ca);
+      if (!CONTRACT_CONDITION (contract)
+	  || CONTRACT_CONDITION_DEFERRED_P (contract)
+	  || CONTRACT_CONDITION (contract) == error_mark_node)
+	return;
+    }
+
+  int flags = SF_DEFAULT | SF_PRE_PARSED;
+  tree finished_pre = NULL_TREE, finished_post = NULL_TREE;
+
+  /* If either the pre or post functions are bad, don't bother emitting
+     any contracts.  The program is already ill-formed.  */
+  tree pre = DECL_PRE_FN (fndecl);
+  tree post = DECL_POST_FN (fndecl);
+  if (pre == error_mark_node || post == error_mark_node)
+    return;
+
+  /* Create a copy of the contracts with references to fndecl's args replaced
+     with references to either the args of pre or post function.  */
+  tree contracts = copy_list (DECL_CONTRACTS (fndecl));
+  for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
+    {
+      tree contract = copy_node (CONTRACT_STATEMENT (attr));
+      if (TREE_CODE (contract) == PRECONDITION_STMT)
+	remap_contract (fndecl, pre, contract, /*duplicate_p=*/false);
+      else if (TREE_CODE (contract) == POSTCONDITION_STMT)
+	remap_contract (fndecl, post, contract, /*duplicate_p=*/false);
+      TREE_VALUE (attr) = build_tree_list (NULL_TREE, contract);
+    }
+
+  if (pre && DECL_INITIAL (fndecl) != error_mark_node)
+    {
+      DECL_PENDING_INLINE_P (pre) = false;
+      start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
+      emit_preconditions (contracts);
+      finished_pre = finish_function (false);
+      expand_or_defer_fn (finished_pre);
+    }
+  if (post && DECL_INITIAL (fndecl) != error_mark_node)
+    {
+      DECL_PENDING_INLINE_P (post) = false;
+      start_preparsed_function (post,
+				DECL_ATTRIBUTES (post),
+				flags);
+      emit_postconditions (contracts);
+
+      tree res = get_postcondition_result_parameter (fndecl);
+      if (res)
+	finish_return_stmt (res);
+      finished_post = finish_function (false);
+      expand_or_defer_fn (finished_post);
+    }
+}
+
 \f
 /* Create the FUNCTION_DECL for a function definition.
    DECLSPECS and DECLARATOR are the parts of the declaration;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 9564b0d619f..8fa0577d3c8 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1420,6 +1420,9 @@ cp_check_const_attributes (tree attributes)
   tree attr;
   for (attr = attributes; attr; attr = TREE_CHAIN (attr))
     {
+      if (cxx_contract_attribute_p (attr))
+	continue;
+
       tree arg;
       for (arg = TREE_VALUE (attr); arg && TREE_CODE (arg) == TREE_LIST;
 	   arg = TREE_CHAIN (arg))
@@ -4461,6 +4464,28 @@ collect_ada_namespace (tree namespc, const char *source_file)
       collect_ada_namespace (decl, source_file);
 }
 
+/* cp_tree_defined_p helper -- returns TP if TP is undefined.  */
+
+static tree
+cp_tree_defined_p_r (tree *tp, int *, void *)
+{
+  enum tree_code code = TREE_CODE (*tp);
+  if ((code == FUNCTION_DECL || code == VAR_DECL)
+      && !decl_defined_p (*tp))
+    return *tp;
+  return NULL_TREE;
+}
+
+/* Returns true iff there is a definition for all entities referenced in the
+   tree TP.  */
+
+bool
+cp_tree_defined_p (tree tp)
+{
+  tree undefined_t = walk_tree (&tp, cp_tree_defined_p_r, NULL, NULL);
+  return !undefined_t;
+}
+
 /* Returns true iff there is a definition available for variable or
    function DECL.  */
 
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 4a89b348829..6c912bc408b 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -557,7 +557,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
       else
 	{
 	  pp_cxx_cv_qualifier_seq (pp, t);
-	  pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t));
+	  if (tree id = TYPE_IDENTIFIER (t))
+	    pp_cxx_tree_identifier (pp, id);
 	}
       break;
 
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index a8cea53cf91..97e0735010a 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -60,6 +60,25 @@ init_exception_processing (void)
 		       && TREE_NOTHROW (terminate_fn));
   pop_nested_namespace (std_node);
 
+  tmp = build_function_type_list (integer_type_node,
+				  boolean_type_node,
+				  integer_type_node,
+				  const_string_type_node,
+				  const_string_type_node,
+				  const_string_type_node,
+				  const_string_type_node,
+				  const_string_type_node,
+				  integer_type_node,
+				  NULL_TREE);
+  on_contract_violation_fn =
+    build_cp_library_fn_ptr ("__on_contract_violation", tmp, ECF_COLD);
+  on_contract_violation_never_fn =
+    build_cp_library_fn_ptr ("__on_contract_violation", tmp,
+			     ECF_COLD | ECF_NORETURN);
+
+  DECL_DECLARED_CONSTEXPR_P (on_contract_violation_never_fn) = true;
+  DECL_DECLARED_CONSTEXPR_P (on_contract_violation_fn) = true;
+
   /* void __cxa_call_unexpected(void *); */
   tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
   call_unexpected_fn
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index ee14c2d5a25..18d8107af55 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -832,6 +832,16 @@ write_encoding (const tree decl)
       write_bare_function_type (fn_type,
 				mangle_return_type_p (decl),
 				d);
+
+      /* If this is the pre/post function for a guarded function, append
+	 pre/post in the vendor specific portion of the mangling.
+
+	 TODO: this likely needs standardizing.
+	 TODO: do we need special handling in other tools like the demangler? */
+      if (DECL_IS_PRE_FN_P (decl))
+	write_string (".pre");
+      else if (DECL_IS_POST_FN_P (decl))
+	write_string (".post");
     }
 }
 
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f259515a498..245ad6ad898 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -9971,6 +9971,20 @@ trees_out::fn_parms_init (tree fn)
 		   base_tag - ix, ix, parm, fn);
       tree_node_vals (parm);
     }
+
+  if (!streaming_p ())
+    {
+      /* We must walk contract attrs so the dependency graph is complete. */
+      for (tree contract = DECL_CONTRACTS (fn);
+	  contract;
+	  contract = CONTRACT_CHAIN (contract))
+	tree_node (contract);
+    }
+
+  /* Write a reference to contracts pre/post functions, if any to avoid
+     regenerating them in importers.  */
+  tree_node (DECL_PRE_FN (fn));
+  tree_node (DECL_POST_FN (fn));
 }
 
 /* Build skeleton parm nodes, read their flags, type & parm indices.  */
@@ -10005,6 +10019,15 @@ trees_in::fn_parms_init (tree fn)
 	return 0;
     }
 
+  /* Reload references to contract functions, if any.  */
+  tree pre_fn = tree_node ();
+  tree post_fn = tree_node ();
+  set_contract_functions (fn, pre_fn, post_fn);
+  if (pre_fn)
+    set_contracts_original_fn (pre_fn, fn);
+  if (post_fn)
+    set_contracts_original_fn (post_fn, fn);
+
   return base_tag;
 }
 
@@ -10590,7 +10613,15 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
 		   Matches decls_match behaviour.  */
 		&& (!DECL_IS_UNDECLARED_BUILTIN (m_inner)
 		    || !DECL_EXTERN_C_P (m_inner)
-		    || DECL_EXTERN_C_P (d_inner)))
+		    || DECL_EXTERN_C_P (d_inner))
+		/* Reject if one is they're different member of a
+		   guarded/pre/post fn set.  */
+		&& (!flag_contracts
+		    || (DECL_IS_PRE_FN_P (d_inner)
+			== DECL_IS_PRE_FN_P (m_inner)))
+		&& (!flag_contracts
+		    || (DECL_IS_POST_FN_P (d_inner)
+			== DECL_IS_POST_FN_P (m_inner))))
 	      {
 		tree m_reqs = get_constraints (m_inner);
 		if (m_reqs)
@@ -14401,6 +14432,7 @@ module_state_config::get_dialect ()
 		      cxx_dialect < cxx20 && flag_concepts ? "/concepts" : "",
 		      flag_coroutines ? "/coroutines" : "",
 		      flag_module_implicit_inline ? "/implicit-inline" : "",
+		      flag_contracts ? "/contracts" : "",
 		      NULL);
 
   return dialect;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ec2065f70c1..38ffe1f7d92 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cp-name-hint.h"
 #include "memmodel.h"
 #include "c-family/known-headers.h"
+#include "contracts.h"
 
 \f
 /* The lexer.  */
@@ -1454,6 +1455,17 @@ cp_ensure_no_oacc_routine (cp_parser *parser)
       parser->oacc_routine = NULL;
     }
 }
+
+/* True if ATTR is an assertion.  */
+
+bool
+cp_contract_assertion_p (const_tree attr)
+{
+  /* This is only an assertion if it is a valid cxx contract attribute and the
+     statement is an ASSERTION_STMT.  */
+  return cxx_contract_attribute_p (attr)
+    && TREE_CODE (CONTRACT_STATEMENT (attr)) == ASSERTION_STMT;
+}
 \f
 /* Decl-specifiers.  */
 
@@ -1474,7 +1486,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
 
 static cp_declarator *make_call_declarator
   (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier,
-   tree, tree, tree, tree, location_t);
+   tree, tree, tree, tree, tree, location_t);
 static cp_declarator *make_array_declarator
   (cp_declarator *, tree);
 static cp_declarator *make_pointer_declarator
@@ -1646,7 +1658,8 @@ make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
 /* Make a declarator for the function given by TARGET, with the
    indicated PARMS.  The CV_QUALIFIERS apply to the function, as in
    "const"-qualified member function.  The EXCEPTION_SPECIFICATION
-   indicates what exceptions can be thrown.  */
+   indicates what exceptions can be thrown.  STD_ATTRS contains
+   attributes and any contracts that apply to the function. */
 
 cp_declarator *
 make_call_declarator (cp_declarator *target,
@@ -1658,6 +1671,7 @@ make_call_declarator (cp_declarator *target,
 		      tree exception_specification,
 		      tree late_return_type,
 		      tree requires_clause,
+		      tree std_attrs,
 		      location_t parens_loc)
 {
   cp_declarator *declarator;
@@ -1682,6 +1696,8 @@ make_call_declarator (cp_declarator *target,
   else
     declarator->parameter_pack_p = false;
 
+  declarator->std_attributes = std_attrs;
+
   return declarator;
 }
 
@@ -1773,23 +1789,32 @@ make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
   return parameter;
 }
 
-/* Returns true iff DECLARATOR  is a declaration for a function.  */
+/* Returns a pointer to the function declarator iff DECLARATOR is a
+   declaration for a function.  Returns NULL otherwise.  */
 
-static bool
-function_declarator_p (const cp_declarator *declarator)
+const cp_declarator *
+find_innermost_function_declarator (const cp_declarator *declarator)
 {
   while (declarator)
     {
       if (declarator->kind == cdk_function
 	  && declarator->declarator->kind == cdk_id)
-	return true;
+	return declarator;
       if (declarator->kind == cdk_id
 	  || declarator->kind == cdk_decomp
 	  || declarator->kind == cdk_error)
-	return false;
+	return NULL;
       declarator = declarator->declarator;
     }
-  return false;
+  return NULL;
+}
+
+/* Returns true iff DECLARATOR  is a declaration for a function.  */
+
+bool
+function_declarator_p (const cp_declarator *declarator)
+{
+  return find_innermost_function_declarator (declarator) != NULL;
 }
 
 /* The parser.  */
@@ -2052,11 +2077,14 @@ cp_parser_context_new (cp_parser_context* next)
   parser->unparsed_queues->last ().nsdmis
 #define unparsed_noexcepts \
   parser->unparsed_queues->last ().noexcepts
+#define unparsed_contracts \
+  parser->unparsed_queues->last ().contracts
 
 static void
 push_unparsed_function_queues (cp_parser *parser)
 {
-  cp_unparsed_functions_entry e = { NULL, make_tree_vector (), NULL, NULL };
+  cp_unparsed_functions_entry e
+      = { NULL, make_tree_vector (), NULL, NULL, NULL };
   vec_safe_push (parser->unparsed_queues, e);
 }
 
@@ -2162,6 +2190,8 @@ static enum tree_code cp_parser_assignment_operator_opt
   (cp_parser *);
 static cp_expr cp_parser_expression
   (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
+static cp_expr cp_parser_conditional_expression
+  (cp_parser *);
 static cp_expr cp_parser_constant_expression
   (cp_parser *, int = 0, bool * = NULL, bool = false);
 static cp_expr cp_parser_builtin_offsetof
@@ -2557,6 +2587,10 @@ static tree cp_parser_transaction_cancel
 static tree cp_parser_yield_expression
   (cp_parser *);
 
+/* Contracts */
+
+static void cp_parser_late_contract_condition
+  (cp_parser *, tree, tree);
 
 enum pragma_context {
   pragma_external,
@@ -2765,6 +2799,8 @@ static bool cp_parser_array_designator_p
   (cp_parser *);
 static bool cp_parser_init_statement_p
   (cp_parser *);
+static bool cp_parser_skip_up_to_closing_square_bracket
+  (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
 static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
@@ -4178,6 +4214,9 @@ cp_parser_new (cp_lexer *lexer)
   /* We are not processing a declarator.  */
   parser->in_declarator_p = false;
 
+  /* We are not parsing a friend declaration.  */
+  parser->declaring_friend_p = false;
+
   /* We are not processing a template-argument-list.  */
   parser->in_template_argument_list_p = false;
 
@@ -10466,15 +10505,7 @@ cp_parser_constant_expression (cp_parser* parser,
      determine whether a particular assignment-expression is in fact
      constant.  */
   if (strict_p)
-    {
-      /* Parse the binary expressions (logical-or-expression).  */
-      expression = cp_parser_binary_expression (parser, false, false, false,
-						PREC_NOT_OPERATOR, NULL);
-      /* If the next token is a `?' then we're actually looking at
-	 a conditional-expression; otherwise we're done.  */
-      if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
-	expression = cp_parser_question_colon_clause (parser, expression);
-    }
+    expression = cp_parser_conditional_expression (parser);
   else
     expression = cp_parser_assignment_expression (parser);
   /* Restore the old settings.  */
@@ -11543,8 +11574,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 				       exception_spec,
 				       return_type,
 				       trailing_requires_clause,
+				       std_attrs,
 				       UNKNOWN_LOCATION);
-    declarator->std_attributes = std_attrs;
 
     fco = grokmethod (&return_type_specs,
 		      declarator,
@@ -11827,6 +11858,16 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
   return attrs;
 }
 
+/* True if and only if the name is one of the contract types.  */
+
+static bool
+contract_attribute_p (const_tree id)
+{
+  return is_attribute_p ("assert", id)
+    || is_attribute_p ("pre", id)
+    || is_attribute_p ("post", id);
+}
+
 /* Parse a statement.
 
    statement:
@@ -11867,7 +11908,10 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
   is a (possibly labeled) if statement which is not enclosed in braces
   and has an else clause.  This is used to implement -Wparentheses.
 
-  CHAIN is a vector of if-else-if conditions.  */
+  CHAIN is a vector of if-else-if conditions.
+
+  Note that this version of parsing restricts assertions to be attached to
+  empty statements. */
 
 static void
 cp_parser_statement (cp_parser* parser, tree in_statement_expr,
@@ -11907,6 +11951,23 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
+
+  /* If we have contracts, check that they're valid in this context.  */
+  if (std_attrs != error_mark_node)
+    {
+      if (tree pre = lookup_attribute ("pre", std_attrs))
+	error_at (EXPR_LOCATION (TREE_VALUE (pre)),
+		  "preconditions cannot be statements");
+      else if (tree post = lookup_attribute ("post", std_attrs))
+	error_at (EXPR_LOCATION (TREE_VALUE (post)),
+		  "postconditions cannot be statements");
+
+    /* Check that assertions are null statements.  */
+    if (cp_contract_assertion_p (std_attrs))
+      if (token->type != CPP_SEMICOLON)
+	error_at (token->location, "assertions must be followed by %<;%>");
+    }
+
   /* Remember the location of the first token in the statement.  */
   cp_token *statement_token = token;
   statement_location = token->location;
@@ -12097,6 +12158,15 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 			"%<fallthrough%> attribute not followed by %<;%>");
 	  std_attrs = NULL_TREE;
 	}
+
+      /* Handle [[assert: ...]];  */
+      if (cp_contract_assertion_p (std_attrs))
+	{
+	  /* Add the assertion as a statement in the current block.  */
+	  gcc_assert (!statement || statement == error_mark_node);
+	  emit_assertion (std_attrs);
+	  std_attrs = NULL_TREE;
+	}
     }
 
   /* Set the line number for the statement.  */
@@ -15201,7 +15271,12 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 		   declared.  */;
 	      else
 		{
-		  if (decl_specs->type && CLASS_TYPE_P (decl_specs->type))
+		  if (find_contract (attrs))
+		    {
+		      diagnose_misapplied_contracts (attrs);
+		      attrs = NULL_TREE;
+		    }
+		  else if (decl_specs->type && CLASS_TYPE_P (decl_specs->type))
 		    {
 		      /*  This is an attribute following a
 			  class-specifier.  */
@@ -16222,6 +16297,21 @@ cp_parser_conversion_declarator_opt (cp_parser* parser)
   return NULL;
 }
 
+/* Parse a conditional-expression.  */
+
+static cp_expr
+cp_parser_conditional_expression (cp_parser *parser)
+{
+  /* Parse the binary expressions (logical-or-expression).  */
+  cp_expr expression = cp_parser_binary_expression (parser, false, false, false,
+						    PREC_NOT_OPERATOR, NULL);
+  /* If the next token is a `?' then we're actually looking at
+     a conditional-expression; otherwise we're done.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
+    expression = cp_parser_question_colon_clause (parser, expression);
+  return expression;
+}
+
 /* Parse an (optional) ctor-initializer.
 
    ctor-initializer:
@@ -22591,7 +22681,10 @@ cp_parser_direct_declarator (cp_parser* parser,
 		    = cp_parser_exception_specification_opt (parser,
 							     flags);
 
+		  bool saved_declaring_friend_p = parser->declaring_friend_p;
+		  parser->declaring_friend_p = friend_p;
 		  attrs = cp_parser_std_attribute_spec_seq (parser);
+		  parser->declaring_friend_p = saved_declaring_friend_p;
 
 		  /* In here, we handle cases where attribute is used after
 		     the function declaration.  For example:
@@ -22617,8 +22710,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 						     exception_specification,
 						     late_return,
 						     requires_clause,
+						     attrs,
 						     parens_loc);
-		  declarator->std_attributes = attrs;
 		  declarator->attributes = gnu_attrs;
 		  /* Any subsequent parameter lists are to do with
 		     return type, so are not those of the declared
@@ -24663,11 +24756,11 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
   return result;
 }
 
-/* Consume tokens up to, and including, the next non-nested closing `]'.
+/* Consume tokens up to, but not including, the next non-nested closing `]'.
    Returns true iff we found a closing `]'.  */
 
 static bool
-cp_parser_skip_to_closing_square_bracket (cp_parser *parser)
+cp_parser_skip_up_to_closing_square_bracket (cp_parser *parser)
 {
   unsigned square_depth = 0;
 
@@ -24692,21 +24785,30 @@ cp_parser_skip_to_closing_square_bracket (cp_parser *parser)
 
         case CPP_CLOSE_SQUARE:
 	  if (!square_depth--)
-	    {
-	      cp_lexer_consume_token (parser->lexer);
-	      return true;
-	    }
+	    return true;
 	  break;
 
 	default:
 	  break;
 	}
 
-      /* Consume the token.  */
+      /* Consume the current token, skipping it.  */
       cp_lexer_consume_token (parser->lexer);
     }
 }
 
+/* Consume tokens up to, and including, the next non-nested closing `]'.
+   Returns true iff we found a closing `]'.  */
+
+static bool
+cp_parser_skip_to_closing_square_bracket (cp_parser *parser)
+{
+  bool found = cp_parser_skip_up_to_closing_square_bracket (parser);
+  if (found)
+    cp_lexer_consume_token (parser->lexer);
+  return found;
+}
+
 /* Return true if we are looking at an array-designator, false otherwise.  */
 
 static bool
@@ -25545,6 +25647,56 @@ cp_parser_class_specifier_1 (cp_parser* parser)
 	  cp_parser_late_parsing_nsdmi (parser, decl);
 	}
       vec_safe_truncate (unparsed_nsdmis, 0);
+
+      /* Now contract attributes.  */
+      FOR_EACH_VEC_SAFE_ELT (unparsed_contracts, ix, decl)
+	{
+	  tree ctx = DECL_CONTEXT (decl);
+	  if (class_type != ctx)
+	    {
+	      if (pushed_scope)
+		pop_scope (pushed_scope);
+	      class_type = ctx;
+	      pushed_scope = push_scope (class_type);
+	    }
+
+	  temp_override<tree> cfd(current_function_decl, decl);
+
+	  /* Make sure that any template parameters are in scope.  */
+	  maybe_begin_member_template_processing (decl);
+
+	  /* Make sure that any member-function parameters are in scope.
+	     This function doesn't expect ccp to be set.  */
+	  current_class_ptr = current_class_ref = NULL_TREE;
+	  inject_parm_decls (decl);
+
+	  /* 'this' is not allowed in static member functions.  */
+	  unsigned char local_variables_forbidden_p
+	    = parser->local_variables_forbidden_p;
+	  if (DECL_THIS_STATIC (decl))
+	    parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
+
+	  /* Now we can parse contract conditions.  */
+	  for (tree a = DECL_ATTRIBUTES (decl); a; a = TREE_CHAIN (a))
+	    {
+	      if (cxx_contract_attribute_p (a))
+		cp_parser_late_contract_condition (parser, decl, a);
+	    }
+
+	  /* Restore the state of local_variables_forbidden_p.  */
+	  parser->local_variables_forbidden_p = local_variables_forbidden_p;
+
+	  /* Remove any member-function parameters from the symbol table.  */
+	  pop_injected_parms ();
+
+	  /* Remove any template parameters from the symbol table.  */
+	  maybe_end_member_template_processing ();
+
+	  /* Perform any deferred contract matching.  */
+	  match_deferred_contracts (decl);
+	}
+      vec_safe_truncate (unparsed_contracts, 0);
+
       current_class_ptr = save_ccp;
       current_class_ref = save_ccr;
       if (pushed_scope)
@@ -25658,6 +25810,8 @@ cp_parser_class_head (cp_parser* parser,
 
   /* Parse the attributes.  */
   attributes = cp_parser_attributes_opt (parser);
+  if (find_contract (attributes))
+    diagnose_misapplied_contracts (attributes);
 
   /* If the next token is `::', that is invalid -- but sometimes
      people do try to write:
@@ -26773,6 +26927,13 @@ cp_parser_member_declaration (cp_parser* parser)
 	      decl = grokfield (declarator, &decl_specifiers,
 				initializer, /*init_const_expr_p=*/true,
 				asm_specification, attributes);
+
+	      /* If we've declared a member function with contracts, ensure we
+		 do late parsing for the contracts even if we have no function
+		 body to parse at that time.  */
+	      if (DECL_DECLARES_FUNCTION_P (decl) && DECL_CONTRACTS (decl))
+		vec_safe_push (unparsed_funs_with_definitions, decl);
+
 	      if (parser->fully_implicit_function_template_p)
 		{
 		  if (friend_p)
@@ -28533,10 +28694,364 @@ cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns)
   return attributes;
 }
 
+/* Optionally parse a C++20 contract role. A NULL return means that no
+   contract role was specified.
+
+    contract-role:
+      % default
+      % identifier
+
+   If the identifier does not name a known contract role, it will
+   be assumed to be default. Returns the identifier for the role
+   token.  */
+
+static tree
+cp_parser_contract_role (cp_parser *parser)
+{
+  gcc_assert (cp_lexer_next_token_is (parser->lexer, CPP_MOD));
+  cp_lexer_consume_token (parser->lexer);
+
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  tree role_id = NULL_TREE;
+  if (token->type == CPP_NAME)
+    role_id = token->u.value;
+  else if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT)
+    role_id = get_identifier ("default");
+  else
+    {
+      error_at (token->location, "expected contract-role");
+      return error_mark_node;
+    }
+  cp_lexer_consume_token (parser->lexer);
+
+  /* FIXME: Warn about invalid/unknown roles?  */
+  return role_id;
+}
+
+/* Parse an optional contract mode.
+
+     contract-mode:
+	contract-semantic
+	[contract-level] [contract-role]
+
+     contract-semantic:
+       check_never_continue
+       check_maybe_continue
+       check_always_continue
+
+     contract-level:
+       default
+       audit
+       axiom
+
+     contract-role:
+       default
+       identifier
+
+   This grammar is taken from P1332R0. During parsing, this sets options
+   on the MODE object to determine the configuration of the contract.
+
+   Returns a tree containing the identifiers used in the configuration.
+   This is either an IDENTIFIER with the literal semantic or a TREE_LIST
+   whose TREE_VALUE is the contract-level and whose TREE_PURPOSE is the
+   contract-role, if any. NULL_TREE is returned if no information is
+   given (i.e., all defaults selected).  */
+
+static tree
+cp_parser_contract_mode_opt (cp_parser *parser,
+			     bool postcondition_p)
+{
+  /* The mode is empty; the level and role are default.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+    return NULL_TREE;
+
+  /* There is only a role; the level is default.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_MOD))
+    {
+      tree role_id = cp_parser_contract_role (parser);
+      return build_tree_list (role_id, get_identifier ("default"));
+    }
+
+  /* Otherwise, match semantic or level.  */
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  contract_level level = CONTRACT_INVALID;
+  contract_semantic semantic = CCS_INVALID;
+  tree config_id;
+  if (token->type == CPP_NAME)
+    {
+      config_id = token->u.value;
+
+      /* Either a named level, a concrete semantic, or an identifier
+	 for a postcondition.  */
+      const char *ident = IDENTIFIER_POINTER (token->u.value);
+      level = map_contract_level (ident);
+      semantic = map_contract_semantic (ident);
+
+      /* The identifier is the return value for a postcondition.  */
+      if (level == CONTRACT_INVALID && semantic == CCS_INVALID
+	  && postcondition_p)
+	return NULL_TREE;
+    }
+  else if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT)
+    {
+      config_id = get_identifier ("default");
+      level = CONTRACT_DEFAULT;
+    }
+  else
+    {
+      /* We got some other token other than a ':'.  */
+      error_at (token->location, "expected contract semantic or level");
+      return NULL_TREE;
+    }
+
+  /* Consume the literal semantic or level token.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  if (semantic == CCS_INVALID && level == CONTRACT_INVALID)
+    {
+      error_at (token->location,
+		"expected contract level: "
+		"%<default%>, %<audit%>, or %<axiom%>");
+      return NULL_TREE;
+    }
+
+  /* We matched an explicit semantic. */
+  if (semantic != CCS_INVALID)
+    {
+      if (cp_lexer_next_token_is (parser->lexer, CPP_MOD))
+	{
+	  error ("invalid use of contract role for explicit semantic");
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_lexer_consume_token (parser->lexer);
+	}
+      return config_id;
+    }
+
+  /* We matched a level, there may be a role; otherwise this is default.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_MOD))
+    {
+      tree role_id = cp_parser_contract_role (parser);
+      return build_tree_list (role_id, config_id);
+    }
+
+  return build_tree_list (NULL_TREE, config_id);
+}
+
+static tree
+find_error (tree *tp, int *, void *)
+{
+  if (*tp == error_mark_node)
+    return *tp;
+  return NULL_TREE;
+}
+
+static bool
+contains_error_p (tree t)
+{
+  return walk_tree (&t, find_error, NULL, NULL);
+}
+
+/* Parse a standard C++20 contract attribute specifier.
+
+  contract-attribute-specifier:
+    [ [ assert contract-level [opt] : conditional-expression ] ]
+    [ [ pre contract-level [opt] : conditional-expression ] ]
+    [ [ post contract-level [opt] identifier [opt] : conditional-expression ] ]
+
+   For free functions, we cannot determine the type of the postcondition
+   identifier because the we haven't called grokdeclarator yet. In those
+   cases we parse the postcondition as if the identifier was declared as
+   'auto <identifier>'. We then instantiate the postcondition once the
+   return type is known.
+
+   For member functions, contracts are in the complete-class context, so the
+   parse is deferred. We also have the return type avaialable (unless it's
+   deduced), so we don't need to parse the postcondition in terms of a
+   placeholder.  */
+
+static tree
+cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute)
+{
+  gcc_assert (contract_attribute_p (attribute));
+  cp_token *token = cp_lexer_consume_token (parser->lexer);
+  location_t loc = token->location;
+
+  bool assertion_p = is_attribute_p ("assert", attribute);
+  bool postcondition_p = is_attribute_p ("post", attribute);
+
+  /* Parse the optional mode.  */
+  tree mode = cp_parser_contract_mode_opt (parser, postcondition_p);
+
+  /* Check for postcondition identifiers.  */
+  cp_expr identifier;
+  if (postcondition_p && cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    identifier = cp_parser_identifier (parser);
+  if (identifier == error_mark_node)
+    return error_mark_node;
+
+  cp_parser_require (parser, CPP_COLON, RT_COLON);
+
+  /* Defer the parsing of pre/post contracts inside class definitions.
+     Note that friends are not member functions and thus not in the complete
+     class context.  */
+  tree contract;
+  if (!assertion_p
+      && current_class_type
+      && TYPE_BEING_DEFINED (current_class_type)
+      && !parser->declaring_friend_p)
+    {
+      /* Skip until we reach an unenclose ']'. If we ran into an unnested ']'
+	 that doesn't close the attribute, return an error and let the attribute
+	 handling code emit an error for missing ']]'.  */
+      cp_token *first = cp_lexer_peek_token (parser->lexer);
+      cp_parser_skip_to_closing_parenthesis_1 (parser,
+					       /*recovering=*/false,
+					       CPP_CLOSE_SQUARE,
+					       /*consume_paren=*/false);
+      if (cp_lexer_peek_token (parser->lexer)->type != CPP_CLOSE_SQUARE
+	  || cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_CLOSE_SQUARE)
+	return error_mark_node;
+      cp_token *last = cp_lexer_peek_token (parser->lexer);
+
+      /* Build a deferred-parse node.  */
+      tree condition = make_node (DEFERRED_PARSE);
+      DEFPARSE_TOKENS (condition) = cp_token_cache_new (first, last);
+      DEFPARSE_INSTANTIATIONS (condition) = NULL;
+
+      /* And it's corresponding contract.  */
+      contract = grok_contract (attribute, mode, identifier, condition, loc);
+    }
+  else
+    {
+      /* Enable location wrappers when parsing contracts.  */
+      auto suppression = make_temp_override (suppress_location_wrappers, 0);
+
+      /* Build a fake variable for the result identifier.  */
+      tree result = NULL_TREE;
+      if (identifier)
+	{
+	  begin_scope (sk_block, NULL_TREE);
+	  result = make_postcondition_variable (identifier);
+	  ++processing_template_decl;
+	}
+
+      /* Parse the condition, ensuring that parameters or the return variable
+	 aren't flagged for use outside the body of a function.  */
+      ++processing_contract_condition;
+      cp_expr condition = cp_parser_conditional_expression (parser);
+      --processing_contract_condition;
+
+      /* Try to recover from errors by scanning up to the end of the
+	 attribute.  Sometimes we get partially parsed expressions, so
+	 we need to search the condition for errors.  */
+      if (contains_error_p (condition))
+	cp_parser_skip_up_to_closing_square_bracket (parser);
+
+      /* Build the contract.  */
+      contract = grok_contract (attribute, mode, result, condition, loc);
+
+      /* Leave our temporary scope for the postcondition result.  */
+      if (result)
+	{
+	  --processing_template_decl;
+	  pop_bindings_and_leave_scope ();
+	}
+    }
+
+  if (!flag_contracts)
+    {
+      error_at (loc, "contracts are only available with %<-fcontracts%>");
+      return error_mark_node;
+    }
+
+  return finish_contract_attribute (attribute, contract);
+}
+
+/* Parse a contract condition for a deferred contract.  */
+
+void cp_parser_late_contract_condition (cp_parser *parser,
+					tree fn,
+					tree attribute)
+{
+  tree contract = TREE_VALUE (TREE_VALUE (attribute));
+
+  /* Make sure we've gotten something that hasn't been parsed yet or that
+     we're not parsing an invalid contract.  */
+  tree condition = CONTRACT_CONDITION (contract);
+  if (TREE_CODE (condition) != DEFERRED_PARSE)
+    return;
+
+  tree identifier = NULL_TREE;
+  if (TREE_CODE (contract) == POSTCONDITION_STMT)
+    identifier = POSTCONDITION_IDENTIFIER (contract);
+
+  /* Build a fake variable for the result identifier.  */
+  tree result = NULL_TREE;
+  if (identifier)
+    {
+      /* TODO: Can we guarantee that the identifier has a location? */
+      location_t loc = cp_expr_location (contract);
+      tree type = TREE_TYPE (TREE_TYPE (fn));
+      if (!check_postcondition_result (fn, type, loc))
+	{
+	  invalidate_contract (contract);
+	  return;
+	}
+
+      begin_scope (sk_block, NULL_TREE);
+      result = make_postcondition_variable (identifier, type);
+      ++processing_template_decl;
+    }
+
+  /* 'this' is not allowed in preconditions of constructors or in postconditions
+     of destructors.  Note that the previous value of this variable is
+     established by the calling function, so we need to save it here.  */
+  tree saved_ccr = current_class_ref;
+  tree saved_ccp = current_class_ptr;
+  if ((DECL_CONSTRUCTOR_P (fn) && PRECONDITION_P (contract)) ||
+       (DECL_DESTRUCTOR_P (fn) && POSTCONDITION_P (contract)))
+    {
+      current_class_ref = current_class_ptr = NULL_TREE;
+      parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
+    }
+
+  push_unparsed_function_queues (parser);
+
+  /* Push the saved tokens onto the parser's lexer stack.  */
+  cp_token_cache *tokens = DEFPARSE_TOKENS (condition);
+  cp_parser_push_lexer_for_tokens (parser, tokens);
+
+  /* Parse the condition, ensuring that parameters or the return variable
+     aren't flagged for use outside the body of a function.  */
+  ++processing_contract_condition;
+  condition = cp_parser_conditional_expression (parser);
+  --processing_contract_condition;
+
+  /* Revert to the main lexer.  */
+  cp_parser_pop_lexer (parser);
+
+  /* Restore the queue.  */
+  pop_unparsed_function_queues (parser);
+
+  current_class_ref = saved_ccr;
+  current_class_ptr = saved_ccp;
+
+  /* Commit to changes.  */
+  update_late_contract (contract, result, condition);
+
+  /* Leave our temporary scope for the postcondition result.  */
+  if (result)
+    {
+      --processing_template_decl;
+      pop_bindings_and_leave_scope ();
+    }
+}
+
 /* Parse a standard C++-11 attribute specifier.
 
    attribute-specifier:
      [ [ attribute-using-prefix [opt] attribute-list ] ]
+     contract-attribute-specifier
      alignment-specifier
 
    attribute-using-prefix:
@@ -28544,7 +29059,15 @@ cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns)
 
    alignment-specifier:
      alignas ( type-id ... [opt] )
-     alignas ( alignment-expression ... [opt] ).  */
+     alignas ( alignment-expression ... [opt] ).
+
+   Extensions for contracts:
+
+   contract-attribute-specifier:
+     [ [ assert :  contract-mode [opt] : conditional-expression ] ]
+     [ [ pre :  contract-mode [opt] : conditional-expression ] ]
+     [ [ post :  contract-mode [opt] identifier [opt] :
+	 conditional-expression ] ]  */
 
 static tree
 cp_parser_std_attribute_spec (cp_parser *parser)
@@ -28556,10 +29079,27 @@ cp_parser_std_attribute_spec (cp_parser *parser)
       && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE)
     {
       tree attr_ns = NULL_TREE;
+      tree attr_name = NULL_TREE;
 
       cp_lexer_consume_token (parser->lexer);
       cp_lexer_consume_token (parser->lexer);
 
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_NAME)
+	{
+	  attr_name = token->u.value;
+	  attr_name = canonicalize_attr_name (attr_name);
+	}
+
+      /* Handle contract-attribute-specs specially.  */
+      if (attr_name && contract_attribute_p (attr_name))
+	{
+	  tree attrs = cp_parser_contract_attribute_spec (parser, attr_name);
+	  if (attrs != error_mark_node)
+	    attributes = attrs;
+	  goto finish_attrs;
+	}
+
       if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
 	{
 	  token = cp_lexer_peek_nth_token (parser->lexer, 2);
@@ -28588,6 +29128,7 @@ cp_parser_std_attribute_spec (cp_parser *parser)
 
       attributes = cp_parser_std_attribute_list (parser, attr_ns);
 
+      finish_attrs:
       if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)
 	  || !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
 	cp_parser_skip_to_end_of_statement (parser);
@@ -30575,6 +31116,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
     cp_parser_ctor_initializer_opt_and_function_body
       (parser, /*in_function_try_block=*/false);
 
+  fn = current_function_decl;
+
   /* Finish the function.  */
   fn = finish_function (inline_p);
 
@@ -31521,6 +32064,16 @@ cp_parser_save_default_args (cp_parser* parser, tree decl)
   tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
   if (UNPARSED_NOEXCEPT_SPEC_P (spec))
     vec_safe_push (unparsed_noexcepts, decl);
+
+  /* If a member function has attributes, they are all deferred.  */
+  for (tree attr = DECL_ATTRIBUTES (decl); attr; attr = TREE_CHAIN (attr))
+    {
+      if (cxx_contract_attribute_p (attr))
+	{
+	  vec_safe_push (unparsed_contracts, decl);
+	  break;
+	}
+    }
 }
 
 /* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 58509256267..ba5afde309d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -217,7 +217,6 @@ static tree get_underlying_template (tree);
 static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
 static tree canonicalize_expr_argument (tree, tsubst_flags_t);
 static tree make_argument_pack (tree);
-static void register_parameter_specializations (tree, tree);
 static tree enclosing_instantiation_of (tree tctx);
 static void instantiate_body (tree pattern, tree args, tree d, bool nested);
 
@@ -1611,8 +1610,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
     {
       if (DECL_TEMPLATE_INSTANTIATION (fn))
 	{
-	  if (DECL_ODR_USED (fn)
-	      || DECL_EXPLICIT_INSTANTIATION (fn))
+	  if (DECL_ODR_USED (fn) || DECL_EXPLICIT_INSTANTIATION (fn))
 	    {
 	      error ("specialization of %qD after instantiation",
 		     fn);
@@ -2015,6 +2013,16 @@ register_local_specialization (tree spec, tree tmpl)
   local_specializations->put (tmpl, spec);
 }
 
+/* Registers T as a specialization of itself.  This is used to preserve
+   the references to already-parsed parameters when instantiating
+   postconditions.  */
+
+void
+register_local_identity (tree t)
+{
+  local_specializations->put (t, t);
+}
+
 /* TYPE is a class type.  Returns true if TYPE is an explicitly
    specialized class.  */
 
@@ -2805,6 +2813,31 @@ warn_spec_missing_attributes (tree tmpl, tree spec, tree attrlist)
 	    pp_formatted_text (&str));
 }
 
+/* Rebuild the attribute list for DECL so that it excludes contracts.
+
+   The function register_specialization() has a tendency to copy attributes
+   from the template being specialized. However, declared specializations can
+   have contracts unrelated to the more general template.  */
+
+static void
+remove_contracts_from_specialization (tree decl)
+{
+  if (decl == error_mark_node)
+    return;
+
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    decl = DECL_TEMPLATE_RESULT (decl);
+
+  tree p = NULL_TREE;
+  for (tree a = DECL_ATTRIBUTES (decl); a; a = TREE_CHAIN (a))
+    {
+      if (!cxx_contract_attribute_p (a))
+	p = tree_cons (TREE_PURPOSE (a), TREE_VALUE (a), p);
+    }
+  nreverse (p);
+  DECL_ATTRIBUTES (decl) = p;
+}
+
 /* Check to see if the function just declared, as indicated in
    DECLARATOR, and in DECL, is a specialization of a function
    template.  We may also discover that the declaration is an explicit
@@ -3219,8 +3252,10 @@ check_explicit_specialization (tree declarator,
 		       parm = DECL_CHAIN (parm))
 		    DECL_CONTEXT (parm) = result;
 		}
-	      return register_specialization (tmpl, gen_tmpl, targs,
+	      decl = register_specialization (tmpl, gen_tmpl, targs,
 					      is_friend, 0);
+	      remove_contracts_from_specialization (decl);
+	      return decl;
 	    }
 
 	  /* Set up the DECL_TEMPLATE_INFO for DECL.  */
@@ -3320,6 +3355,10 @@ check_explicit_specialization (tree declarator,
 					      is_friend, 0);
 	    }
 
+	  /* If this is a specialization, splice any contracts that may have
+	     been inherited from the template, removing them.  */
+	  if (decl != error_mark_node && DECL_TEMPLATE_SPECIALIZATION (decl))
+	    remove_contracts_from_specialization (decl);
 
 	  /* A 'structor should already have clones.  */
 	  gcc_assert (decl == error_mark_node
@@ -11441,6 +11480,113 @@ can_complete_type_without_circularity (tree type)
 static tree tsubst_omp_clauses (tree, enum c_omp_region_type, tree,
 				tsubst_flags_t, tree);
 
+/* Instantiate the contract statement.  */
+
+static tree
+tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
+		 tree in_decl)
+{
+  tree type = decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE;
+  bool auto_p  = type_uses_auto (type);
+
+  tree r = copy_node (t);
+
+  /* Rebuild the result variable.  */
+  if (POSTCONDITION_P (t) && POSTCONDITION_IDENTIFIER (t))
+    {
+      tree oldvar = POSTCONDITION_IDENTIFIER (t);
+
+      tree newvar = copy_node (oldvar);
+      TREE_TYPE (newvar) = type;
+      DECL_CONTEXT (newvar) = decl;
+      POSTCONDITION_IDENTIFIER (r) = newvar;
+
+      /* Make sure the postcondition is valid.  */
+      location_t loc = DECL_SOURCE_LOCATION (oldvar);
+      if (!auto_p)
+	if (!check_postcondition_result (decl, type, loc))
+	  return invalidate_contract (r);
+
+      /* Make the variable available for lookup.  */
+      register_local_specialization (newvar, oldvar);
+    }
+
+  /* Instantiate the condition.  If the return type is undeduced, process
+     the expression as if inside a template to avoid spurious type errors.  */
+  if (auto_p)
+    ++processing_template_decl;
+  ++processing_contract_condition;
+  CONTRACT_CONDITION (r)
+      = tsubst_expr (CONTRACT_CONDITION (t), args, complain, in_decl, false);
+  --processing_contract_condition;
+  if (auto_p)
+    --processing_template_decl;
+
+  /* And the comment.  */
+  CONTRACT_COMMENT (r)
+      = tsubst_expr (CONTRACT_COMMENT (r), args, complain, in_decl, false);
+
+  return r;
+}
+
+/* Update T by instantiating its contract attribute.  */
+
+static void
+tsubst_contract_attribute (tree decl, tree t, tree args,
+			   tsubst_flags_t complain, tree in_decl)
+{
+  /* For non-specializations, adjust the current declaration to the most general
+     version of in_decl. Because we defer the instantiation of contracts as long
+     as possible, they are still written in terms of the parameters (and return
+     type) of the most general template.  */
+  tree tmpl = DECL_TI_TEMPLATE (in_decl);
+  if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
+    in_decl = DECL_TEMPLATE_RESULT (most_general_template (in_decl));
+  local_specialization_stack specs (lss_copy);
+  register_parameter_specializations (in_decl, decl);
+
+  /* Get the contract to be instantiated.  */
+  tree contract = CONTRACT_STATEMENT (t);
+
+  /* Use the complete set of template arguments for instantiation. The
+     contract may not have been instantiated and still refer to outer levels
+     of template parameters.  */
+  args = DECL_TI_ARGS (decl);
+
+  /* For member functions, make this available for semantic analysis.  */
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
+    {
+      tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
+      tree this_type = TREE_TYPE (TREE_VALUE (arg_types));
+      inject_this_parameter (this_type, cp_type_quals (this_type));
+    }
+
+  contract = tsubst_contract (decl, contract, args, complain, in_decl);
+
+  current_class_ptr = save_ccp;
+  current_class_ref = save_ccr;
+
+  /* Rebuild the attribute.  */
+  TREE_VALUE (t) = build_tree_list (NULL_TREE, contract);
+}
+
+/* Rebuild the attribute list for DECL, substituting into contracts
+   as needed.  */
+
+void
+tsubst_contract_attributes (tree decl, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  tree list = copy_list (DECL_ATTRIBUTES (decl));
+  for (tree attr = list; attr; attr = CONTRACT_CHAIN (attr))
+    {
+      if (cxx_contract_attribute_p (attr))
+	tsubst_contract_attribute (decl, attr, args, complain, in_decl);
+    }
+  DECL_ATTRIBUTES (decl) = list;
+}
+
 /* Instantiate a single dependent attribute T (a TREE_LIST), and return either
    T or a new TREE_LIST, possibly a chain in the case of a pack expansion.  */
 
@@ -11450,6 +11596,10 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 {
   gcc_assert (ATTR_IS_DEPENDENT (t));
 
+  /* Note that contract attributes are never substituted from this function.
+     Their instantiation is triggered by regenerate_from_template_decl when
+     we instantiate the body of the function.  */
+
   tree val = TREE_VALUE (t);
   if (val == NULL_TREE)
     /* Nothing to do.  */;
@@ -16719,7 +16869,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 			  = do_auto_deduction (TREE_TYPE (r), init, auto_node,
 					       complain, adc_variable_type);
 		    }
-		  gcc_assert (cp_unevaluated_operand || TREE_STATIC (r)
+		  gcc_assert (cp_unevaluated_operand
+			      || processing_contract_condition
+			      || TREE_STATIC (r)
 			      || decl_constant_var_p (r)
 			      || seen_error ());
 		  if (!processing_template_decl
@@ -18179,6 +18331,19 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
       finish_using_directive (USING_STMT_NAMESPACE (t), /*attribs=*/NULL_TREE);
       break;
 
+    case PRECONDITION_STMT:
+    case POSTCONDITION_STMT:
+      gcc_unreachable ();
+
+    case ASSERTION_STMT:
+      {
+	r = tsubst_contract (NULL_TREE, t, args, complain, in_decl);
+	if (r != error_mark_node)
+	  add_stmt (r);
+	RETURN (r);
+      }
+      break;
+
     case DECL_EXPR:
       {
 	tree decl, pattern_decl;
@@ -19770,6 +19935,14 @@ tsubst_copy_and_build (tree t,
 				RECUR (TREE_OPERAND (t, 0)),
 				complain|decltype_flag));
 
+    case FLOAT_EXPR:
+      /* FIXME: This case was taken out, presumably because everything is
+	 moving to use IMPLICIT_CONV_EXPR. However, cvt.c is still producing
+	 FLOAT_EXPRs in some cases.  */
+      if (!type_dependent_expression_p (TREE_OPERAND (t, 0)))
+	return t;
+      /* Fall through. */
+
     case FIX_TRUNC_EXPR:
       /* convert_like should have created an IMPLICIT_CONV_EXPR.  */
       gcc_unreachable ();
@@ -25459,6 +25632,21 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args)
 	    DECL_CONTEXT (t) = decl;
 	}
 
+      if (DECL_CONTRACTS (decl))
+	{
+	  /* If we're regenerating a specialization, the contracts will have
+	     been copied from the most general template. Replace those with
+	     the ones from the actual specialization.  */
+	  tree tmpl = DECL_TI_TEMPLATE (decl);
+	  if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
+	    {
+	      remove_contracts_from_specialization (decl);
+	      copy_contract_attributes (decl, code_pattern);
+	    }
+
+	  tsubst_contract_attributes (decl, args, tf_warning_or_error, code_pattern);
+	}
+
       /* Merge additional specifiers from the CODE_PATTERN.  */
       if (DECL_DECLARED_INLINE_P (code_pattern)
 	  && !DECL_DECLARED_INLINE_P (decl))
@@ -25710,7 +25898,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
 /* We're starting to process the function INST, an instantiation of PATTERN;
    add their parameters to local_specializations.  */
 
-static void
+void
 register_parameter_specializations (tree pattern, tree inst)
 {
   tree tmpl_parm = DECL_ARGUMENTS (pattern);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 7b183685476..f6233589e6c 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "tree-inline.h"
 
 static int is_subobject_of_p (tree, tree);
 static tree dfs_lookup_base (tree, void *);
@@ -1917,6 +1918,38 @@ maybe_check_overriding_exception_spec (tree overrider, tree basefn)
   return true;
 }
 
+/* Replace the any contract attributes on OVERRIDER with a copy where any
+   references to BASEFN's PARM_DECLs have been rewritten to the corresponding
+   PARM_DECL in OVERRIDER.  */
+
+static void
+inherit_base_contracts (tree overrider, tree basefn)
+{
+  tree last = NULL_TREE, contract_attrs = NULL_TREE;
+  for (tree a = DECL_CONTRACTS (basefn);
+      a != NULL_TREE;
+      a = CONTRACT_CHAIN (a))
+    {
+      tree c = copy_node (a);
+      TREE_VALUE (c) = build_tree_list (TREE_PURPOSE (TREE_VALUE (c)),
+					copy_node (CONTRACT_STATEMENT (c)));
+
+      tree src = basefn;
+      tree dst = overrider;
+      remap_contract (src, dst, CONTRACT_STATEMENT (c), /*duplicate_p=*/true);
+
+      CONTRACT_COMMENT (CONTRACT_STATEMENT (c)) =
+	copy_node (CONTRACT_COMMENT (CONTRACT_STATEMENT (c)));
+
+      chainon (last, c);
+      last = c;
+      if (!contract_attrs)
+	contract_attrs = c;
+    }
+
+  set_decl_contracts (overrider, contract_attrs);
+}
+
 /* Check that virtual overrider OVERRIDER is acceptable for base function
    BASEFN. Issue diagnostic, and return zero, if unacceptable.  */
 
@@ -2076,6 +2109,33 @@ check_final_overrider (tree overrider, tree basefn)
 	}
       return 0;
     }
+
+  if (!DECL_HAS_CONTRACTS_P (basefn) && DECL_HAS_CONTRACTS_P (overrider))
+    {
+      auto_diagnostic_group d;
+      error ("function with contracts %q+D overriding contractless function",
+	     overrider);
+      inform (DECL_SOURCE_LOCATION (basefn),
+	      "overridden function is %qD", basefn);
+      return 0;
+    }
+  else if (DECL_HAS_CONTRACTS_P (basefn) && !DECL_HAS_CONTRACTS_P (overrider))
+    {
+      /* We're inheriting basefn's contracts; create a copy of them but
+	 replace references to their parms to our parms.  */
+      inherit_base_contracts (overrider, basefn);
+    }
+  else if (DECL_HAS_CONTRACTS_P (basefn) && DECL_HAS_CONTRACTS_P (overrider))
+    {
+      /* We're in the process of completing the overrider's class, which means
+	 our conditions definitely are not parsed so simply chain on the
+	 basefn for later checking.
+
+	 Note that OVERRIDER's contracts will have been fully parsed at the
+	 point the deferred match is run.  */
+      defer_guarded_contract_match (overrider, basefn, DECL_CONTRACTS (basefn));
+    }
+
   if (DECL_FINAL_P (basefn))
     {
       auto_diagnostic_group d;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b080259083e..f05614b6cf1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "predict.h"
 #include "memmodel.h"
+#include "contracts.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
@@ -718,6 +719,531 @@ end_maybe_infinite_loop (tree cond)
     }
 }
 
+/* Build and return an argument list using all the arguments passed to the
+   (presumably guarded) FUNCTION_DECL FN.  This can be used to forward all of
+   FN's arguments to a function taking the same list of arguments -- namely
+   the unchecked form of FN. */
+
+vec<tree, va_gc> *
+build_arg_list (tree fn)
+{
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+
+  vec<tree, va_gc> *args = make_tree_vector ();
+  for (tree t = DECL_ARGUMENTS (fn); t != NULL_TREE; t = TREE_CHAIN (t))
+    {
+      if (is_this_parameter (t))
+	continue; // skip already inserted `this` args
+
+      vec_safe_push (args, forward_parm (t));
+    }
+  return args;
+}
+
+/* Map from FUNCTION_DECL to a FUNCTION_DECL for either the PRE_FN or POST_FN.
+   These are used to parse contract conditions and are called inside the body
+   of the guarded function.  */
+static GTY(()) hash_map<tree, tree> *decl_pre_fn;
+static GTY(()) hash_map<tree, tree> *decl_post_fn;
+static GTY(()) hash_map<tree, tree> *decl_original_fn;
+
+/* Returns the precondition funtion for D, or null if not set.  */
+
+tree
+get_precondition_function (tree d)
+{
+  hash_map_maybe_create<hm_ggc> (decl_pre_fn);
+  tree *result = decl_pre_fn->get (d);
+  return result ? *result : NULL_TREE;
+}
+
+/* Returns the postcondition funtion for D, or null if not set.  */
+
+tree
+get_postcondition_function (tree d)
+{
+  hash_map_maybe_create<hm_ggc> (decl_post_fn);
+  tree *result = decl_post_fn->get (d);
+  return result ? *result : NULL_TREE;
+}
+
+/* Makes PRE the precondition function for D.  */
+
+void
+set_precondition_function (tree d, tree pre)
+{
+  gcc_assert (pre);
+  hash_map_maybe_create<hm_ggc> (decl_pre_fn);
+  gcc_assert (!decl_pre_fn->get (d));
+  decl_pre_fn->put (d, pre);
+}
+
+/* Makes POST the postcondition function for D.  */
+
+void
+set_postcondition_function (tree d, tree post)
+{
+  gcc_assert (post);
+  hash_map_maybe_create<hm_ggc> (decl_post_fn);
+  gcc_assert (!decl_post_fn->get (d));
+  decl_post_fn->put (d, post);
+}
+
+/* Set the PRE and POST functions for D.  Note that PRE and POST can be
+   null in this case. If so the functions are not recorded.  */
+
+void
+set_contract_functions (tree d, tree pre, tree post)
+{
+  if (pre)
+    set_precondition_function (d, pre);
+  if (post)
+    set_postcondition_function (d, post);
+}
+
+/* Returns the original guarded function of a precondition or postcondition
+   function D, or null if it does not exist.  */
+
+tree
+get_contracts_original_fn (tree d)
+{
+  hash_map_maybe_create<hm_ggc> (decl_original_fn);
+  tree *result = decl_original_fn->get (d);
+  return result ? *result : NULL_TREE;
+}
+
+
+/* Set the original fn for a contract function D.  */
+
+void
+set_contracts_original_fn (tree d, tree orig)
+{
+  gcc_assert (orig);
+  hash_map_maybe_create<hm_ggc> (decl_original_fn);
+
+  /* FIXME: Why are we resetting the contract function? This is called
+     from finish_function, but seems to just re-assert that the original
+     function is the same.  */
+  if (tree p = get_contracts_original_fn (d))
+    gcc_assert (p == orig);
+
+  decl_original_fn->put (d, orig);
+}
+
+/* Return a copy of the FUNCTION_DECL IDECL with its own unshared
+   PARM_DECL and DECL_ATTRIBUTEs.  */
+
+static tree
+copy_fn_decl (tree idecl)
+{
+  tree decl = copy_decl (idecl);
+  DECL_ATTRIBUTES (decl) = copy_list (DECL_ATTRIBUTES (idecl));
+
+  if (DECL_RESULT (idecl))
+    {
+      DECL_RESULT (decl) = copy_decl (DECL_RESULT (idecl));
+      DECL_CONTEXT (DECL_RESULT (decl)) = decl;
+    }
+  if (!DECL_ARGUMENTS (idecl) || VOID_TYPE_P (DECL_ARGUMENTS (idecl)))
+    return decl;
+
+  tree last = DECL_ARGUMENTS (decl) = copy_decl (DECL_ARGUMENTS (decl));
+  DECL_CONTEXT (last) = decl;
+  for (tree p = TREE_CHAIN (DECL_ARGUMENTS (idecl)); p; p = TREE_CHAIN (p))
+    {
+      if (VOID_TYPE_P (p))
+	{
+	  TREE_CHAIN (last) = void_list_node;
+	  break;
+	}
+      last = TREE_CHAIN (last) = copy_decl (p);
+      DECL_CONTEXT (last) = decl;
+    }
+  return decl;
+}
+
+/* Build a declaration for the pre- or postcondition of a guarded FNDECL.  */
+
+static tree
+build_contract_condition_function (tree fndecl, bool pre)
+{
+  if (TREE_TYPE (fndecl) == error_mark_node)
+    return error_mark_node;
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
+      && !TYPE_METHOD_BASETYPE (TREE_TYPE (fndecl)))
+    return error_mark_node;
+
+  /* Create and rename the unchecked function and give an internal name.  */
+  tree fn = copy_fn_decl (fndecl);
+  DECL_RESULT (fn) = NULL_TREE;
+  tree value_type = pre ? void_type_node : TREE_TYPE (TREE_TYPE (fn));
+
+  /* Don't propagate declaration attributes to the checking function,
+     including the original contracts.  */
+  DECL_ATTRIBUTES (fn) = NULL_TREE;
+
+  tree arg_types = NULL_TREE;
+  tree *last = &arg_types;
+
+  /* FIXME will later optimizations delete unused args to prevent extra arg
+   * passing? do we care? */
+  tree class_type = NULL_TREE;
+  for (tree arg_type = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      arg_type && arg_type != void_list_node;
+      arg_type = TREE_CHAIN (arg_type))
+    {
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
+	  && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type)
+      {
+	class_type = TREE_TYPE (TREE_VALUE (arg_type));
+	continue;
+      }
+      *last = build_tree_list (TREE_PURPOSE (arg_type), TREE_VALUE (arg_type));
+      last = &TREE_CHAIN (*last);
+    }
+
+  if (pre || VOID_TYPE_P (value_type))
+    *last = void_list_node;
+  else
+    {
+      /* FIXME do we need magic to perfectly forward this so we don't clobber
+	 RVO/NRVO etc?  */
+      tree name = get_identifier ("__r");
+      tree parm = build_lang_decl (PARM_DECL, name, value_type);
+      DECL_CONTEXT (parm) = fn;
+      DECL_ARGUMENTS (fn) = chainon (DECL_ARGUMENTS (fn), parm);
+
+      *last = build_tree_list (NULL_TREE, value_type);
+      TREE_CHAIN (*last) = void_list_node;
+    }
+
+  TREE_TYPE (fn) = build_function_type (value_type, arg_types);
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
+    TREE_TYPE (fn) = build_method_type (class_type, TREE_TYPE (fn));
+
+  DECL_NAME (fn) = copy_node (DECL_NAME (fn));
+  DECL_INITIAL (fn) = error_mark_node;
+  set_contracts_original_fn (fn, fndecl);
+
+  IDENTIFIER_VIRTUAL_P (DECL_NAME (fn)) = false;
+  DECL_VIRTUAL_P (fn) = false;
+
+  /* Update various inline related declaration properties.  */
+  //DECL_DECLARED_INLINE_P (fn) = true;
+  DECL_DISREGARD_INLINE_LIMITS (fn) = true;
+  TREE_NO_WARNING (fn) = 1;
+
+  return fn;
+}
+
+static bool
+has_active_contract_condition (tree d, tree_code c)
+{
+  for (tree as = DECL_CONTRACTS (d) ; as != NULL_TREE; as = TREE_CHAIN (as))
+    {
+      tree contract = TREE_VALUE (TREE_VALUE (as));
+      if (TREE_CODE (contract) == c && contract_active_p (contract))
+	return true;
+    }
+  return false;
+}
+
+/* True if D has any checked or assumed preconditions.  */
+
+static bool
+has_active_preconditions (tree d)
+{
+  return has_active_contract_condition (d, PRECONDITION_STMT);
+}
+
+/* True if D has any checked or assumed postconditions.  */
+
+static bool
+has_active_postconditions (tree d)
+{
+  return has_active_contract_condition (d, POSTCONDITION_STMT);
+}
+
+/* Build the precondition checking function for D.  */
+
+static tree
+build_precondition_function (tree d)
+{
+  if (!has_active_preconditions (d))
+    return NULL_TREE;
+
+  return build_contract_condition_function (d, /*pre=*/true);
+}
+
+/* Build the postcondition checking function for D. If the return
+   type is undeduced, don't build the function yet. We do that in
+   apply_deduced_return_type.  */
+
+static tree
+build_postcondition_function (tree d)
+{
+  if (!has_active_postconditions (d))
+    return NULL_TREE;
+
+  tree type = TREE_TYPE (TREE_TYPE (d));
+  if (is_auto (type))
+    return NULL_TREE;
+
+  return build_contract_condition_function (d, /*pre=*/false);
+}
+
+void
+build_contract_function_decls (tree d)
+{
+  /* Constructors and destructors have their contracts inserted inline.  */
+  if (DECL_CONSTRUCTOR_P (d) || DECL_DESTRUCTOR_P (d))
+    return;
+
+  /* Build the pre/post functions (or not).  */
+  tree pre = build_precondition_function (d);
+  tree post = build_postcondition_function (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)
+{
+  if (CONTRACT_LITERAL_MODE_P (contract))
+    return "";
+  if (tree mode = CONTRACT_MODE (contract))
+    if (tree level = TREE_VALUE (mode))
+      return IDENTIFIER_POINTER (level);
+  return "default";
+}
+
+static const char *
+get_contract_role_name (tree contract)
+{
+  if (CONTRACT_LITERAL_MODE_P (contract))
+    return "";
+  if (tree mode = CONTRACT_MODE (contract))
+    if (tree role = TREE_PURPOSE (mode))
+      return IDENTIFIER_POINTER (role);
+  return "default";
+}
+
+static void
+build_contract_handler_fn (tree contract,
+			   contract_continuation cmode)
+{
+  const char *level = get_contract_level_name (contract);
+  const char *role = get_contract_role_name (contract);
+  tree comment = CONTRACT_COMMENT (contract);
+
+  expanded_location loc = expand_location (EXPR_LOCATION (contract));
+
+  tree continue_mode = build_int_cst (boolean_type_node, cmode != NEVER_CONTINUE);
+  tree line_number = build_int_cst (integer_type_node, loc.line);
+  tree file_name = build_string_literal (strlen (loc.file) + 1, loc.file);
+  const char *function_name_str =
+    TREE_CODE (contract) == ASSERTION_STMT
+      || DECL_CONSTRUCTOR_P (current_function_decl)
+      || DECL_DESTRUCTOR_P (current_function_decl)
+    ? current_function_name ()
+    : fndecl_name (DECL_ORIGINAL_FN (current_function_decl));
+  tree function_name = build_string_literal (strlen (function_name_str) + 1,
+					     function_name_str);
+  tree level_str = build_string_literal (strlen (level) + 1, level);
+  tree role_str = build_string_literal (strlen (role) + 1, role);
+
+  /* FIXME: Do we want a string for this?.  */
+  tree continuation = build_int_cst (integer_type_node, cmode);
+
+  tree violation_fn;
+  if (cmode == MAYBE_CONTINUE)
+    violation_fn = on_contract_violation_fn;
+  else
+    violation_fn = on_contract_violation_never_fn;
+  tree call = build_call_expr (violation_fn, 8, continue_mode, line_number,
+			       file_name, function_name, comment,
+			       level_str, role_str,
+			       continuation);
+
+  finish_expr_stmt (call);
+}
+
+/* Return true if CONTRACT is checked or assumed under the current build
+   configuration. */
+
+bool
+contract_active_p (tree contract)
+{
+  return get_contract_semantic (contract) != CCS_IGNORE;
+}
+
+/* Return true if any contract in the CONTRACT list is checked or assumed
+   under the current build configuration. */
+
+bool
+contract_any_active_p (tree contract)
+{
+  for (; contract != NULL_TREE; contract = CONTRACT_CHAIN (contract))
+    if (contract_active_p (TREE_VALUE (TREE_VALUE (contract))))
+      return true;
+  return false;
+}
+
+/* Generate the code that checks or assumes a contract, but do not attach
+   it to the current context.  This is called during genericization.  */
+
+tree
+build_contract_check (tree contract)
+{
+  contract_semantic semantic = get_contract_semantic (contract);
+  if (semantic == CCS_INVALID)
+    return NULL_TREE;
+
+  /* Ignored contracts are never checked or assumed.  */
+  if (semantic == CCS_IGNORE)
+    return build1 (NOP_EXPR, void_type_node, integer_zero_node);
+
+  remap_dummy_this (current_function_decl, &CONTRACT_CONDITION (contract));
+  tree condition = CONTRACT_CONDITION (contract);
+  if (condition == error_mark_node)
+    return NULL_TREE;
+
+  /* If an assumed contract condition is not fully defined, the current method
+     of turning it into a compile time assumption fails and emits run time
+     code.  We don't want that, so just turn these into NOP.  */
+  if (semantic == CCS_ASSUME && !cp_tree_defined_p (condition))
+    return build1 (NOP_EXPR, void_type_node, integer_zero_node);
+
+  tree if_stmt = begin_if_stmt ();
+  tree cond = build_x_unary_op (EXPR_LOCATION (contract),
+				TRUTH_NOT_EXPR,
+				condition,
+				tf_warning_or_error);
+  finish_if_stmt_cond (cond, if_stmt);
+
+  if (semantic == CCS_ASSUME)
+    {
+      tree unreachable_fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+      tree call = build_call_expr (unreachable_fn, 0);
+      finish_expr_stmt (call);
+    }
+  else
+    {
+      /* Get the continuation mode.  */
+      contract_continuation cmode;
+      switch (semantic)
+	{
+	  case CCS_NEVER: cmode = NEVER_CONTINUE; break;
+	  case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
+	  default: gcc_unreachable ();
+	}
+
+      build_contract_handler_fn (contract, cmode);
+    }
+
+  finish_then_clause (if_stmt);
+  tree scope = IF_SCOPE (if_stmt);
+  IF_SCOPE (if_stmt) = NULL;
+  return do_poplevel (scope);
+}
+
+/* Generate the statement for the given contract attribute by adding the
+   statement to the current block. Returns the next contract in the chain.  */
+
+static tree
+emit_contract_statement (tree attr)
+{
+  gcc_assert (TREE_CODE (attr) == TREE_LIST);
+  tree contract = CONTRACT_STATEMENT (attr);
+
+  /* Only add valid contracts.  */
+  if (get_contract_semantic (contract) != CCS_INVALID
+      && CONTRACT_CONDITION (contract) != error_mark_node)
+    add_stmt (contract);
+
+  return CONTRACT_CHAIN (attr);
+}
+
+/* Add the statements of contract attributes ATTRS to the current block.  */
+
+static void
+emit_contract_conditions (tree attrs, tree_code code)
+{
+  if (!attrs) return;
+  gcc_assert (TREE_CODE (attrs) == TREE_LIST);
+  gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
+  while (attrs)
+    {
+      tree contract = CONTRACT_STATEMENT (attrs);
+      if (TREE_CODE (contract) == code)
+	attrs = emit_contract_statement (attrs);
+      else
+	attrs = CONTRACT_CHAIN (attrs);
+    }
+}
+
+/* Emit the statement for an assertion attribute.  */
+
+void
+emit_assertion (tree attr)
+{
+  emit_contract_statement (attr);
+}
+
+/* Emit statements for precondition attributes.  */
+
+void
+emit_preconditions (tree attr)
+{
+  return emit_contract_conditions (attr, PRECONDITION_STMT);
+}
+
+/* Emit statements for postcondition attributes.  */
+
+void
+emit_postconditions (tree contracts)
+{
+  return emit_contract_conditions (contracts, POSTCONDITION_STMT);
+}
+
+/* Converts a contract condition to bool and ensures it has a locaiton.  */
+
+tree
+finish_contract_condition (cp_expr condition)
+{
+  /* Ensure we have the condition location saved in case we later need to
+     emit a conversion error during template instantiation and wouldn't
+     otherwise have it.  */
+  if (!CAN_HAVE_LOCATION_P (condition) || EXCEPTIONAL_CLASS_P (condition))
+    {
+      condition = build1_loc (condition.get_location (), VIEW_CONVERT_EXPR,
+			      TREE_TYPE (condition), condition);
+      EXPR_LOCATION_WRAPPER_P (condition) = 1;
+    }
+
+  if (condition == error_mark_node || type_dependent_expression_p (condition))
+    return condition;
+
+  return maybe_convert_cond (condition);
+}
 
 /* Begin a conditional that might contain a declaration.  When generating
    normal code, we want the declaration to appear before the statement
@@ -1206,9 +1732,7 @@ finish_return_stmt (tree expr)
       if (warn_sequence_point)
 	verify_sequence_points (expr);
 
-      if (DECL_DESTRUCTOR_P (current_function_decl)
-	  || (DECL_CONSTRUCTOR_P (current_function_decl)
-	      && targetm.cxx.cdtor_returns_this ()))
+      if (DECL_CDTOR_NEEDS_LABLED_EXIT_P (current_function_decl))
 	{
 	  /* Similarly, all destructors must run destructors for
 	     base-classes before returning.  So, all returns in a
@@ -2029,7 +2553,10 @@ finish_mem_initializers (tree mem_inits)
 				  CTOR_INITIALIZER, mem_inits));
     }
   else
-    emit_mem_initializers (mem_inits);
+    {
+      emit_preconditions (DECL_CONTRACTS (current_function_decl));
+      emit_mem_initializers (mem_inits);
+    }
 }
 
 /* Obfuscate EXPR if it looks like an id-expression or member access so
@@ -2155,12 +2682,21 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 
   /* DR 613/850: Can use non-static data members without an associated
      object in sizeof/decltype/alignof.  */
-  if (is_dummy_object (object) && cp_unevaluated_operand == 0
+  if (is_dummy_object (object)
+      && !cp_unevaluated_operand
       && (!processing_template_decl || !current_class_ref))
     {
       if (current_function_decl
 	  && DECL_STATIC_FUNCTION_P (current_function_decl))
 	error ("invalid use of member %qD in static member function", decl);
+      else if (current_function_decl
+	       && processing_contract_condition
+	       && DECL_CONSTRUCTOR_P (current_function_decl))
+	error ("invalid use of member %qD in constructor %<pre%> contract", decl);
+      else if (current_function_decl
+	       && processing_contract_condition
+	       && DECL_DESTRUCTOR_P (current_function_decl))
+	error ("invalid use of member %qD in destructor %<post%> contract", decl);
       else
 	error ("invalid use of non-static data member %qD", decl);
       inform (DECL_SOURCE_LOCATION (decl), "declared here");
@@ -2970,6 +3506,10 @@ finish_this_expr (void)
   tree fn = current_nonlambda_function ();
   if (fn && DECL_STATIC_FUNCTION_P (fn))
     error ("%<this%> is unavailable for static member functions");
+  else if (fn && processing_contract_condition && DECL_CONSTRUCTOR_P (fn))
+    error ("invalid use of %<this%> before it is valid");
+  else if (fn && processing_contract_condition && DECL_DESTRUCTOR_P (fn))
+    error ("invalid use of %<this%> after it is valid");
   else if (fn)
     error ("invalid use of %<this%> in non-member function");
   else
@@ -3867,6 +4407,9 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
 	}
       return error_mark_node;
     }
+  else if (processing_contract_condition && (TREE_CODE (decl) == PARM_DECL))
+    /* Use of a parameter in a contract condition is fine.  */
+    return decl;
   else
     {
       if (complain & tf_error)
@@ -3999,7 +4542,8 @@ finish_id_expression_1 (tree id_expression,
 	 body, except inside an unevaluated context (i.e. decltype).  */
       if (TREE_CODE (decl) == PARM_DECL
 	  && DECL_CONTEXT (decl) == NULL_TREE
-	  && !cp_unevaluated_operand)
+	  && !cp_unevaluated_operand
+	  && !processing_contract_condition)
 	{
 	  *error_msg = G_("use of parameter outside function body");
 	  return error_mark_node;
@@ -10854,6 +11398,18 @@ apply_deduced_return_type (tree fco, tree return_type)
 
   TREE_TYPE (fco) = change_return_type (return_type, TREE_TYPE (fco));
 
+  /* Update any postconditions and the postcondition checking function
+     as needed.  If there are postconditions, we'll use those to rewrite
+     return statements to check postconditions.  */
+  if (has_active_postconditions (fco))
+    {
+      rebuild_postconditions (fco, return_type);
+      tree post = build_postcondition_function (fco);
+      set_postcondition_function (fco, post);
+    }
+
+  /* Apply the type to the result object.  */
+
   result = DECL_RESULT (fco);
   if (result == NULL_TREE)
     return;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2a14fa92ddb..80c3874b84c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -46,6 +46,7 @@ static tree verify_stmt_tree_r (tree *, int *, void *);
 
 static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
 static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
+static tree handle_contract_attribute (tree *, tree, tree, int, bool *);
 
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
    Otherwise, returns clk_none.  */
@@ -3777,6 +3778,50 @@ called_fns_equal (tree t1, tree t2)
     return cp_tree_equal (t1, t2);
 }
 
+bool comparing_override_contracts;
+
+/* In a component reference, return the innermost object of
+   the postfix-expression.  */
+
+static tree
+get_innermost_component (tree t)
+{
+  gcc_assert (TREE_CODE (t) == COMPONENT_REF);
+  while (TREE_CODE (t) == COMPONENT_REF)
+    t = TREE_OPERAND (t, 0);
+  return t;
+}
+
+/* Returns true if T is a possibly converted 'this' or '*this' expression.  */
+
+static bool
+is_this_expression (tree t)
+{
+  t = get_innermost_component (t);
+  /* See through deferences and no-op conversions.  */
+  if (TREE_CODE (t) == INDIRECT_REF)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == NOP_EXPR)
+    t = TREE_OPERAND (t, 0);
+  return is_this_parameter (t);
+}
+
+static bool
+comparing_this_references (tree t1, tree t2)
+{
+  return is_this_expression (t1) && is_this_expression (t2);
+}
+
+static bool
+equivalent_member_references (tree t1, tree t2)
+{
+  if (!comparing_this_references (t1, t2))
+    return false;
+  t1 = TREE_OPERAND (t1, 1);
+  t2 = TREE_OPERAND (t2, 1);
+  return t1 == t2;
+}
+
 /* Return truthvalue of whether T1 is the same tree structure as T2.
    Return 1 if they are the same. Return 0 if they are different.  */
 
@@ -4111,6 +4156,13 @@ cp_tree_equal (tree t1, tree t2)
 	return false;
       return true;
 
+    case COMPONENT_REF:
+      /* If we're comparing contract conditions of overrides, member references
+	 compare equal if they designate the same member.  */
+      if (comparing_override_contracts)
+	return equivalent_member_references (t1, t2);
+      break;
+
     default:
       break;
     }
@@ -4897,6 +4949,8 @@ const struct attribute_spec std_attribute_table[] =
     handle_likeliness_attribute, attr_cold_hot_exclusions },
   { "noreturn", 0, 0, true, false, false, false,
     handle_noreturn_attribute, attr_noreturn_exclusions },
+  { "pre", 0, -1, false, false, false, false, handle_contract_attribute, NULL },
+  { "post", 0, -1, false, false, false, false, handle_contract_attribute, NULL },
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
 };
 
@@ -5145,6 +5199,17 @@ handle_abi_tag_attribute (tree* node, tree name, tree args,
   return NULL_TREE;
 }
 
+/* Perform checking for contract attributes.  */
+
+tree
+handle_contract_attribute (tree *ARG_UNUSED (node), tree ARG_UNUSED (name),
+			   tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			   bool *ARG_UNUSED (no_add_attrs))
+{
+  /* TODO: Is there any checking we could do here?  */
+  return NULL_TREE;
+}
+
 /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
    thing pointed to by the constant.  */
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a483e1f988d..ac91024121e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -10075,6 +10075,39 @@ maybe_warn_pessimizing_move (tree retval, tree functype)
     }
 }
 
+/* Rewrite the expression of a returned expression so that it invokes the
+   postcondition function as needed.  */
+
+static tree
+apply_postcondition_to_return (tree post, tree expr)
+{
+  if (!expr || expr == error_mark_node)
+    return expr;
+
+  vec<tree, va_gc> *args = build_arg_list (current_function_decl);
+
+  // FIXME: do we need forward_parm or similar?
+  if (get_postcondition_result_parameter (current_function_decl))
+    vec_safe_push (args, expr);
+
+  push_deferring_access_checks (dk_no_check);
+  tree call = finish_call_expr (post,
+				&args,
+				/*disallow_virtual=*/true,
+				/*koenig_p=*/false,
+				/*complain=*/tf_warning_or_error);
+  gcc_assert (call != error_mark_node);
+
+  /* We may not have actually built a CALL_EXPR; for instance if the
+     return type is large (contracts-large-return.C).  */
+  if (TREE_CODE (call) == CALL_EXPR)
+    CALL_FROM_THUNK_P (call) = 1;
+
+  pop_deferring_access_checks ();
+
+  return call;
+}
+
 /* Check that returning RETVAL from the current function is valid.
    Return an expression explicitly showing all conversions required to
    change RETVAL into the function return type, and to assign it to
@@ -10289,6 +10322,12 @@ check_return_expr (tree retval, bool *no_warning)
       return retval;
     }
 
+  /* If there's a postcondition, rewrite the return expression with a
+     call to the postcondition function.  */
+  if (!processing_template_decl)
+    if (tree post = DECL_POST_FN (current_function_decl))
+      retval = apply_postcondition_to_return (post, retval);
+
   /* The fabled Named Return Value optimization, as per [class.copy]/15:
 
      [...]      For  a function with a class return type, if the expression
diff --git a/gcc/input.c b/gcc/input.c
index de20d983d2c..7704bd64607 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -836,6 +836,89 @@ location_get_source_line (const char *file_path, int line)
   return char_span (buffer, len);
 }
 
+/* Return the source text between two locations.  */
+
+char *
+get_source (location_t start, location_t end)
+{
+  expanded_location expstart =
+    expand_location_to_spelling_point (start, LOCATION_ASPECT_START);
+  expanded_location expend =
+    expand_location_to_spelling_point (end, LOCATION_ASPECT_FINISH);
+
+  /* If the locations are in different files or the end comes before the
+     start, abort and return nothing.  */
+  if (!expstart.file || !expend.file)
+    return NULL;
+  if (strcmp (expstart.file, expend.file) != 0)
+    return NULL;
+  if (expstart.line > expend.line)
+    return NULL;
+  if (expstart.line == expend.line
+      && expstart.column > expend.column)
+    return NULL;
+
+  /* For a single line we need to trim both edges.  */
+  if (expstart.line == expend.line)
+    {
+      char_span line = location_get_source_line (expstart.file, expstart.line);
+      if (line.length () < 1)
+	return NULL;
+      int s = expstart.column - 1;
+      int l = expend.column - expstart.column + 1;
+      if (line.length () < (size_t)s + l)
+	return NULL;
+      return line.subspan (s, l).xstrdup ();
+    }
+
+  /* FIXME how should we handle newlines and runs of spaces?  */
+  char buf[1024 + 4]{};
+  char *res = buf;
+  size_t len = 1024;
+
+  /* Loop through all lines in the range and append each to buf; may trim
+     parts of the start and end lines off depending on column values.  */
+  for (int l = expstart.line; len > 0 && l <= expend.line; ++l)
+    {
+      char_span line = location_get_source_line (expstart.file, l);
+      if (line.length () < 1 && (l != expstart.line && l != expend.line))
+	continue;
+
+      /* for the first line in the range, only start at expstart.column */
+      if (l == expstart.line)
+	{
+	  if (expstart.column == 0)
+	    return NULL;
+	  if (line.length () < (size_t)expstart.column - 1)
+	    return NULL;
+	  line = line.subspan (expstart.column - 1,
+			       line.length() - expstart.column + 1);
+	}
+      /* for the last line, don't go past expstart.column */
+      else if (l == expend.line)
+	{
+	  if (line.length () < (size_t)expend.column)
+	    return NULL;
+	  line = line.subspan (0, expend.column);
+	}
+
+      /* if we've run out of buffer, truncate the line */
+      if (line.length() >= len)
+	line = line.subspan (0, len);
+
+      gcc_assert (line.length () <= len);
+      strncat (res, line.get_buffer (), line.length ());
+      res += line.length ();
+      len -= line.length ();
+    }
+
+  /* If we ran out of space, add a '...' abbreviation marker. */
+  if (len <= 0)
+    buf[1024] = buf[1025] = buf[1026] = '.';
+
+  return xstrdup (buf);
+}
+
 /* Determine if FILE_PATH missing a trailing newline on its final line.
    Only valid to call once all of the file has been loaded, by
    requesting a line number beyond the end of the file.  */
diff --git a/gcc/testsuite/contracts/backtrace_handler/assert_fail.cpp b/gcc/testsuite/contracts/backtrace_handler/assert_fail.cpp
new file mode 100644
index 00000000000..08c64bc2849
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/assert_fail.cpp
@@ -0,0 +1,23 @@
+void fun1() {
+  int x = 0;
+  [[ assert: x < 0 ]];
+}
+namespace tns {
+  void fun2() {
+    fun1();
+  }
+}
+template<typename T>
+void fun3(T a) {
+  tns::fun2();
+}
+void fun4() {
+  fun3(5);
+}
+int main(int, char**) {
+  void (*fp)() = nullptr;
+  fp = fun4;
+  fp();
+  return 0;
+}
+
diff --git a/gcc/testsuite/contracts/backtrace_handler/handle_contract_violation.cpp b/gcc/testsuite/contracts/backtrace_handler/handle_contract_violation.cpp
new file mode 100644
index 00000000000..bfbb97ec02e
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/handle_contract_violation.cpp
@@ -0,0 +1,26 @@
+#include <iostream>
+#include <contract>
+#include <execinfo.h>
+#include <unistd.h>
+
+static constexpr int MAX_BACKTRACE_DEPTH = 128;
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  size_t _backtraceSize{0};
+  void *_backtrace[MAX_BACKTRACE_DEPTH]{};
+
+  _backtraceSize = backtrace(_backtrace, MAX_BACKTRACE_DEPTH);
+  if(_backtraceSize == MAX_BACKTRACE_DEPTH)
+    std::cerr << "warning: backtrace may have been truncated" << std::endl;
+
+  std::cerr << "contract violation: " << violation.file_name()
+    << ":" << violation.line_number()
+    << ": " << violation.comment() << " is false"
+    << " [with contract level=" << violation.assertion_level() << "]" << std::endl
+    << "violation occurs here:" << std::endl;
+  // skip the stack frame of handle_contract_violation and
+  // on_contract_violation to get to wherever the assert was
+  backtrace_symbols_fd(_backtrace + 2, _backtraceSize - 1, STDERR_FILENO);
+  std::cerr << "end of violation" << std::endl;
+}
+
diff --git a/gcc/testsuite/contracts/except_preload_handler/assert_fail.cpp b/gcc/testsuite/contracts/except_preload_handler/assert_fail.cpp
new file mode 100644
index 00000000000..3dda7ac84d5
--- /dev/null
+++ b/gcc/testsuite/contracts/except_preload_handler/assert_fail.cpp
@@ -0,0 +1,20 @@
+#include <iostream>
+#include <contract>
+
+int fun() {
+	int x = 0;
+	[[ assert: x < 0 ]];
+
+	return 0;
+}
+
+int main(int argc, char**) {
+	try {
+		fun();
+	} catch(int &ex) {
+		std::cerr << "synth caught indirect: " << ex << std::endl;
+	}
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/contracts/except_preload_handler/handle_contract_violation.cpp b/gcc/testsuite/contracts/except_preload_handler/handle_contract_violation.cpp
new file mode 100644
index 00000000000..ec051b39e5f
--- /dev/null
+++ b/gcc/testsuite/contracts/except_preload_handler/handle_contract_violation.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+#include <contract>
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom handle_contract_violation: " << std::endl
+    << " line_number: " << violation.line_number() << std::endl
+    << " file_name: " << violation.file_name() << std::endl
+    << " function_name: " << violation.function_name() << std::endl
+    << " comment: " << violation.comment() << std::endl
+    << " assertion_level: " << violation.assertion_level() << std::endl
+    << std::endl;
+  throw -1;
+}
+
diff --git a/gcc/testsuite/contracts/noexcept_preload_handler/assert_fail.cpp b/gcc/testsuite/contracts/noexcept_preload_handler/assert_fail.cpp
new file mode 100644
index 00000000000..8ae98fbe668
--- /dev/null
+++ b/gcc/testsuite/contracts/noexcept_preload_handler/assert_fail.cpp
@@ -0,0 +1,20 @@
+#include <iostream>
+#include <contract>
+
+int fun() noexcept {
+	int x = 0;
+	[[ assert: x < 0 ]];
+
+	return 0;
+}
+
+int main(int argc, char**) {
+	try {
+		fun();
+	} catch(int &ex) {
+		std::cerr << "synth caught indirect: " << ex << std::endl;
+	}
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/contracts/noexcept_preload_handler/handle_contract_violation.cpp b/gcc/testsuite/contracts/noexcept_preload_handler/handle_contract_violation.cpp
new file mode 100644
index 00000000000..ec051b39e5f
--- /dev/null
+++ b/gcc/testsuite/contracts/noexcept_preload_handler/handle_contract_violation.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+#include <contract>
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom handle_contract_violation: " << std::endl
+    << " line_number: " << violation.line_number() << std::endl
+    << " file_name: " << violation.file_name() << std::endl
+    << " function_name: " << violation.function_name() << std::endl
+    << " comment: " << violation.comment() << std::endl
+    << " assertion_level: " << violation.assertion_level() << std::endl
+    << std::endl;
+  throw -1;
+}
+
diff --git a/gcc/testsuite/contracts/preload_handler/assert_fail.cpp b/gcc/testsuite/contracts/preload_handler/assert_fail.cpp
new file mode 100644
index 00000000000..0f807db0628
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_handler/assert_fail.cpp
@@ -0,0 +1,7 @@
+int main(int, char**) {
+	int x = 0;
+	[[ assert: x < 0 ]];
+
+	return 0;
+}
+
diff --git a/gcc/testsuite/contracts/preload_handler/handle_contract_violation.cpp b/gcc/testsuite/contracts/preload_handler/handle_contract_violation.cpp
new file mode 100644
index 00000000000..6029875ee6c
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_handler/handle_contract_violation.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <contract>
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom handle_contract_violation: " << std::endl
+    << " line_number: " << violation.line_number() << std::endl
+    << " file_name: " << violation.file_name() << std::endl
+    << " function_name: " << violation.function_name() << std::endl
+    << " comment: " << violation.comment() << std::endl
+    << " assertion_level: " << violation.assertion_level() << std::endl
+    << " assertion_role: " << violation.assertion_role() << std::endl
+    << " continuation_mode: " << (int)violation.continuation_mode() << std::endl
+    << std::endl;
+}
+
diff --git a/gcc/testsuite/contracts/preload_nocontinue_handler/assert_fail.cpp b/gcc/testsuite/contracts/preload_nocontinue_handler/assert_fail.cpp
new file mode 100644
index 00000000000..a17a6239bb7
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_nocontinue_handler/assert_fail.cpp
@@ -0,0 +1,10 @@
+#include <iostream>
+
+int main(int, char**) {
+	int x = 0;
+	[[ assert: x < 0 ]];
+
+	std::cout << "returning from main" << std::endl;
+	return 0;
+}
+
diff --git a/gcc/testsuite/contracts/preload_nocontinue_handler/handle_contract_violation.cpp b/gcc/testsuite/contracts/preload_nocontinue_handler/handle_contract_violation.cpp
new file mode 100644
index 00000000000..8499483c86b
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_nocontinue_handler/handle_contract_violation.cpp
@@ -0,0 +1,13 @@
+#include <iostream>
+#include <contract>
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom handle_contract_violation: " << std::endl
+    << " line_number: " << violation.line_number() << std::endl
+    << " file_name: " << violation.file_name() << std::endl
+    << " function_name: " << violation.function_name() << std::endl
+    << " comment: " << violation.comment() << std::endl
+    << " assertion_level: " << violation.assertion_level() << std::endl
+    << std::endl;
+}
+
diff --git a/gcc/testsuite/contracts/preload_nocontinue_handler/nocontinue.cpp b/gcc/testsuite/contracts/preload_nocontinue_handler/nocontinue.cpp
new file mode 100644
index 00000000000..2a7d53e353d
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_nocontinue_handler/nocontinue.cpp
@@ -0,0 +1,19 @@
+#include <exception>
+#include <contract>
+#include <dlfcn.h>
+
+using handler = void (*)(const std::contract_violation &);
+constexpr const char *mangledHandlerName = "_Z25handle_contract_violationRKSt18contract_violation";
+void handle_contract_violation(const std::contract_violation &violation) {
+  try {
+    handler original_handle_contract_violation;
+    original_handle_contract_violation =
+      (handler)dlsym(RTLD_NEXT, mangledHandlerName);
+    (*original_handle_contract_violation)(violation);
+  }
+  catch(...) {
+    ; // squash
+  }
+  std::terminate();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-access1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-access1.C
new file mode 100644
index 00000000000..a3a29821017
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-access1.C
@@ -0,0 +1,128 @@
+// ensure that that preconditions can access public, protected, and private
+// members of the current and base classes
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+struct Base
+{
+  int pub{-1};
+
+  virtual int b()
+    [[ pre: pub > 0 ]]
+    [[ pre: pro > 0 ]]
+    [[ pre: pri > 0 ]]
+  {
+    return pub * pro * pri;
+  }
+
+  protected:
+    int pro{-1};
+    int pri{-1};
+};
+
+struct Child : Base
+{
+  int fun()
+    [[ pre: pub > 0 ]]
+    [[ pre: pro > 0 ]]
+    [[ pre: pri > 0 ]]
+  {
+    return pub * pro;
+  }
+};
+
+struct VChild : Base
+{
+  int b()
+    [[ pre: pub > 0 ]]
+    [[ pre: pro > 0 ]]
+    [[ pre: pri > 0 ]]
+  {
+    return pub * pro;
+  }
+};
+
+template<typename B>
+struct TChild : B
+{
+  int fun()
+    [[ pre: B::pub > 0 ]]
+    [[ pre: B::pro > 0 ]]
+    [[ pre: B::pri > 0 ]]
+  {
+    return B::pub * B::pro;
+  }
+};
+
+struct PubBase
+{
+  int pub{-1};
+  int pro{-1};
+  int pri{-1};
+};
+
+struct PubChild : PubBase
+{
+  int fun()
+    [[ pre: pub > 0 ]]
+    [[ pre: pro > 0 ]]
+    [[ pre: pri > 0 ]]
+  {
+    return pub * pro;
+  }
+};
+
+template<typename B>
+struct TPubChild : B
+{
+  int fun()
+    [[ pre: B::pub > 0 ]]
+    [[ pre: B::pro > 0 ]]
+    [[ pre: B::pri > 0 ]]
+  {
+    return B::pub * B::pro;
+  }
+};
+
+int main()
+{
+  Base base{};
+  base.b();
+
+  Child child{};
+  child.fun();
+
+  VChild vchild{};
+  vchild.b();
+
+  TChild<Base> tchild{};
+  tchild.fun();
+
+  PubChild pubchild{};
+  pubchild.fun();
+
+  TPubChild<PubBase> tpubchild;
+  tpubchild.fun();
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 11 Base::b .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 Base::b .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 13 Base::b .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 26 Child::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 27 Child::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 Child::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 37 VChild::b .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 VChild::b .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 VChild::b .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 49 TChild<Base>::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 50 TChild<Base>::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 51 TChild<Base>::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 67 PubChild::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 PubChild::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 69 PubChild::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 79 TPubChild<PubBase>::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 80 TPubChild<PubBase>::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 81 TPubChild<PubBase>::fun .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-assume1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-assume1.C
new file mode 100644
index 00000000000..71388501ea7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-assume1.C
@@ -0,0 +1,30 @@
+// test that assumed contracts do instatiate templates
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+template<typename T>
+int f(T t)
+{
+  return -t;
+}
+
+int dummy()
+{
+  [[ assert assume: f(1.0) > 0 ]];
+  return -1;
+}
+
+template<>
+int f(double t) // { dg-error "specialization of.*after instantiation" }
+{
+  return -1.0;
+}
+
+int main()
+{
+  dummy();
+  f(1);
+  f(1.0);
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-assume2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-assume2.C
new file mode 100644
index 00000000000..af163eddcf2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-assume2.C
@@ -0,0 +1,34 @@
+// ensure that assert contracts can be turned into compile time assumptions
+// and that they can be used for optimization.
+//
+// Even though x == -1, the assert contract tells the compiler that it is
+// safe to assume the x <= 0 branch is never taken fun can be transformed into
+// just
+//   printf("%d: test x>0\n", x);
+//   return 0;
+// we ensure this by matching on the output and expecting a 0 return code from
+// main -- unlike contracts-ignore2 which expects a failing return code
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-role=default:never,assume,ignore -O1" }
+#include <cstdio>
+
+int fun(int x) {
+  [[assert audit: x > 0]];
+  if(x <= 0)
+  {
+    printf("%d: test x<=0 opt out\n", x);
+    return -1;
+  }
+  else
+  {
+    printf("%d: test x>0\n", x);
+    return 0;
+  }
+}
+
+int main(int, char**) {
+  volatile int x = -1;
+  return fun(x);
+}
+
+// { dg-output "-1: test x>0(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-assume3.C b/gcc/testsuite/g++.dg/cpp2a/contracts-assume3.C
new file mode 100644
index 00000000000..8dad6bb562e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-assume3.C
@@ -0,0 +1,19 @@
+// test that assumed contracts that reference undefined entities do not cause
+// a link failure
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+
+int f(int t);
+
+int dummy()
+{
+  [[ assert assume: f(1) > 0 ]];
+  return -1;
+}
+
+int main()
+{
+  dummy();
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-assume4.C b/gcc/testsuite/g++.dg/cpp2a/contracts-assume4.C
new file mode 100644
index 00000000000..7954f531612
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-assume4.C
@@ -0,0 +1,19 @@
+// test that assumed constexpr contracts that reference undefined entities do
+// not cause constexpr eval failure
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+
+constexpr int f(int t); // { dg-warning "used but never defined" }
+
+constexpr int dummy()
+{
+  [[ assert assume: f(1) > 0 ]];
+  return -1;
+}
+
+int main()
+{
+  constexpr int n = dummy();
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-assume5.C b/gcc/testsuite/g++.dg/cpp2a/contracts-assume5.C
new file mode 100644
index 00000000000..67b28647786
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-assume5.C
@@ -0,0 +1,35 @@
+// test that assumed constexpr contracts that reference defined entities cause
+// constexpr eval failure when the predicate is constexpr false
+// test that assumed constexpr contracts that reference undefined entities in
+// an unevaluated context cause constexpr eval failure
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+constexpr int f(int t)
+{
+  return -1;
+}
+
+constexpr int dummy()
+{
+  [[ assert assume: f(1) > 0 ]];
+  return -1;
+}
+
+constexpr int undef(int t);
+
+constexpr int dummy2()
+{
+  [[ assert assume: sizeof(decltype(f(1))) < 0 ]];
+  return -1;
+}
+
+int main()
+{
+  constexpr int n = dummy(); // { dg-message "in .constexpr. expansion" }
+  // { dg-error "contract predicate" "" { target *-*-* } 15 }
+  constexpr int m = dummy2(); // { dg-message "in .constexpr. expansion" }
+  // { dg-error "contract predicate" "" { target *-*-* } 23 }
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-assume6.C b/gcc/testsuite/g++.dg/cpp2a/contracts-assume6.C
new file mode 100644
index 00000000000..931c4d0c19c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-assume6.C
@@ -0,0 +1,61 @@
+// ensure that non-defined entities in assume contracts do not error
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+template<typename T>
+T id2(T n);
+
+int fun(int n)
+  [[ pre assume: id2(n) > 0 ]]
+  [[ pre: n > 0 ]]
+{
+  return -n;
+}
+
+template<typename T>
+T tfun(T n)
+  [[ pre assume: id2(n) > 0 ]]
+  [[ pre: n > 0 ]]
+{
+  return -n;
+}
+
+template<typename T>
+constexpr T id(T n); // { dg-warning "used but never defined" }
+
+template<typename T>
+constexpr T cfun(T n)
+  [[ pre assume: id(n) > 0 ]]
+  [[ pre: id(n) > 0 ]] // { dg-error "used before its definition" }
+{
+  return -n;
+}
+
+template<typename T>
+constexpr T id3(T n)
+{
+  return n;
+}
+
+template<typename T>
+constexpr T cfun2(T n)
+  [[ pre assume: id3(n) > 0 ]] // { dg-error "contract predicate" }
+{
+  return -n;
+}
+
+template<typename T>
+constexpr T cfun3(T n)
+  [[ pre: id3(n) > 0 ]] // { dg-error "contract predicate" }
+{
+  return -n;
+}
+
+int main() {
+  constexpr int n = cfun(-5);
+  constexpr int n2 = cfun2(-5);
+  constexpr int n3 = cfun3(-5);
+  fun(-5);
+  tfun(-5);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-config1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-config1.C
new file mode 100644
index 00000000000..9e32bac535d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-config1.C
@@ -0,0 +1,36 @@
+// Small test to ensure that the level and role information printed by various
+// contract configurations is correct.
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-role=default:maybe,maybe,ignore" }
+
+int fun(int n)
+  [[ post default r: r > 0 ]]
+{
+  return -n;
+}
+
+int main(int, char **)
+{
+  [[ assert default: false ]];
+  [[ assert: false ]];
+  [[ assert audit: false ]];
+  [[ assert default %new_role: false ]];
+  [[ assert %new_role: false ]];
+  [[ assert audit %new_role: false ]];
+  [[ assert check_maybe_continue: false ]];
+  [[ assert %default: false ]];
+  [[ assert audit %default: false ]];
+  fun(5);
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*main false default default 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false default default 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false audit default 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false default new_role 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false default new_role 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false audit new_role 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false   1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false default default 1.*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*main false audit default 1.*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-constexpr1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-constexpr1.C
new file mode 100644
index 00000000000..4c111358d9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-constexpr1.C
@@ -0,0 +1,74 @@
+// ensure that passing pre/post do not affect constexpr functions
+// ensure that failing pre/post generate an error at runtime in constexpr funcs
+// { dg-do run }
+// { dg-options "-std=c++20 -fcontracts -fcontract-continuation-mode=on" }
+
+constexpr int wfun(int a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return a;
+}
+
+constexpr int ffun(int a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return a;
+}
+
+template<typename T>
+constexpr int tfun(T a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return a;
+}
+
+template<typename T>
+constexpr int wtfun(T a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return a;
+}
+
+template<typename T>
+constexpr int ftfun(T a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return a;
+}
+
+constexpr int explicitfn(int a)
+  [[ pre ignore: a > 0 ]]
+  [[ pre check_maybe_continue: a > 0 ]]
+  [[ post ignore r: r > 0 ]]
+  [[ post check_maybe_continue r: r > 0 ]]
+{
+  return a;
+}
+
+int main(int, char **) {
+  constexpr int a = wfun(10);
+  int b = ffun(-10);
+  constexpr int c = wtfun(10);
+  int d = ftfun(-10);
+
+  int e = explicitfn(-10);
+
+  int z = ftfun(-10.0);
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 14 ffun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 15 ffun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 ftfun<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 ftfun<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 46 explicitfn .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 48 explicitfn .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 ftfun<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 ftfun<double> .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-constexpr2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-constexpr2.C
new file mode 100644
index 00000000000..d0d41f05927
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-constexpr2.C
@@ -0,0 +1,58 @@
+// ensure that failing pre/post can fail at constexpr time
+// { dg-do compile }
+// { dg-options "-std=c++20 -fcontracts -fcontract-continuation-mode=on" }
+
+constexpr int ffun(int a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 10 ]]
+{
+  return a;
+}
+
+template<typename T>
+constexpr int ftfun(T a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 10 ]]
+{
+  return a;
+}
+
+constexpr int explicitfn(int a)
+  [[ pre ignore: a > 0 ]]
+  [[ pre check_maybe_continue: a > 0 ]]
+  [[ post ignore r: r > 10 ]]
+  [[ post check_maybe_continue r: r > 10 ]]
+{
+  return a;
+}
+
+template<typename T>
+constexpr int ftfun2(T a)
+  [[ pre: a > 0 ]]
+  [[ post r: r > 10 ]]
+{
+  return a;
+}
+
+int main(int, char **) {
+  constexpr int a = ffun(-10);
+  // { dg-error "contract predicate" "" { target *-*-* } 6 }
+  constexpr int b = ftfun(-10);
+  // { dg-error "contract predicate" "" { target *-*-* } 14 }
+  constexpr int c = explicitfn(-10);
+  // { dg-error "contract predicate" "" { target *-*-* } 22 }
+  constexpr int d = ftfun2(-10.0);
+  // { dg-error "contract predicate" "" { target *-*-* } 31 }
+
+  constexpr int e = ffun(5);
+  // { dg-error "contract predicate" "" { target *-*-* } 7 }
+  constexpr int f = ftfun(5);
+  // { dg-error "contract predicate" "" { target *-*-* } 15 }
+  constexpr int g = explicitfn(5);
+  // { dg-error "contract predicate" "" { target *-*-* } 24 }
+  constexpr int h = ftfun2(5.5);
+  // { dg-error "contract predicate" "" { target *-*-* } 32 }
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-conversion1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-conversion1.C
new file mode 100644
index 00000000000..ff5e23f2f14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-conversion1.C
@@ -0,0 +1,19 @@
+// Test to ensure that diagnostic location for condition conversion is in the
+// right place.
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+
+template<typename T>
+void fn()
+  [[ pre: T{} ]] // { dg-error "no match" }
+{
+}
+
+struct Z { };
+
+int main(int, char**) {
+  fn<int>();
+  fn<Z>();
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor1.C
new file mode 100644
index 00000000000..bcd6096b5a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor1.C
@@ -0,0 +1,177 @@
+// Tests to ensure that contracts are properly emitted for constructors,
+// destructors, and their intersection with templates.
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+bool pre_{false}, post_{false};
+bool delegate_{false};
+
+struct S
+{
+  S() [[ pre: pre_ ]] [[ post: post_ ]];
+  ~S() [[ pre: pre_ ]] [[ post: post_ ]];
+};
+
+S::S() { return; }
+S::~S() { return; }
+
+struct SInline
+{
+  SInline() [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+  ~SInline() [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+};
+
+struct SDelegate0
+{
+  SDelegate0(int) [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+  SDelegate0() : SDelegate0(0) { return; }
+  ~SDelegate0() [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+};
+
+struct SDelegate1
+{
+  SDelegate1(int) { return; }
+  SDelegate1() [[ pre: pre_ ]] [[ post: post_ ]] : SDelegate1(0) { return; }
+  ~SDelegate1() [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+};
+
+struct SDelegate2
+{
+  SDelegate2(int) [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+  SDelegate2() [[ pre: pre_ && delegate_ ]] [[ post: post_ && delegate_ ]] : SDelegate2(0) { return; }
+  ~SDelegate2() [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+};
+
+struct SDelegate3
+{
+  SDelegate3(int) [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+  SDelegate3() [[ pre: pre_ && delegate_ ]] [[ post: post_ && delegate_ ]] : SDelegate3(0) { return; }
+  ~SDelegate3() [[ pre: pre_ ]] [[ post: post_ ]] { return; }
+};
+
+template<typename T>
+struct S1
+{
+  S1() [[ pre: pre_ ]] [[ post: post_ ]] { }
+};
+
+struct S2
+{
+  template<typename T>
+  S2(T) [[ pre: pre_ ]] [[ post: post_ ]] { }
+};
+
+template<typename T>
+struct S3
+{
+  template<typename S>
+  S3(S) [[ pre: pre_ ]] [[ post: post_ ]] { }
+};
+
+struct G0
+{
+  G0() [[ post: x > 0 ]] {}
+  ~G0() [[ pre: x > 0 ]] {}
+  int x{-1};
+};
+
+struct G1
+{
+  G1() [[ post: this->x > 0 ]] {}
+  ~G1() [[ pre: this->x > 0 ]] {}
+  int x{-1};
+};
+
+int x{-1};
+
+struct G2
+{
+  G2() [[ pre: ::x > 0 ]] {}
+  ~G2() [[ post: ::x > 0 ]] {}
+  int x{1};
+};
+
+void test0()
+{
+  S s;
+  SInline si;
+  SDelegate0 sd0;
+  SDelegate1 sd1;
+  SDelegate2 sd2;
+  SDelegate3 sd3;
+  S1<int> s1_i;
+  S1<double> s1_d;
+  S2 s2_i{1};
+  S2 s2_d{.1};
+  S3<int> s3_i_i{1};
+  S3<int> s3_i_d{.1};
+  S3<double> s3_d_i{1};
+  S3<double> s3_d_d{.1};
+}
+
+void test1()
+{
+  G0 g0;
+  G1 g1;
+  G2 g2;
+}
+
+int main(int, char**)
+{
+  test0();
+  test1();
+  return 0;
+};
+
+// test0
+// { dg-output "default std::handle_contract_violation called: .*.C 11 S::S .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 S::S .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 20 SInline::SInline .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 20 SInline::SInline .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 26 SDelegate0::SDelegate0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 26 SDelegate0::SDelegate0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 34 SDelegate1::SDelegate1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 34 SDelegate1::SDelegate1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 41 SDelegate2::SDelegate2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 40 SDelegate2::SDelegate2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 40 SDelegate2::SDelegate2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 41 SDelegate2::SDelegate2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 48 SDelegate3::SDelegate3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 47 SDelegate3::SDelegate3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 47 SDelegate3::SDelegate3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 48 SDelegate3::SDelegate3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 S1<int>::S1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 S1<int>::S1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 S1<double>::S1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 S1<double>::S1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 61 S2::S2<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 61 S2::S2<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 61 S2::S2<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 61 S2::S2<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<int>::S3<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<int>::S3<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<int>::S3<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<int>::S3<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<double>::S3<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<double>::S3<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<double>::S3<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 S3<double>::S3<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 49 SDelegate3::~SDelegate3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 49 SDelegate3::~SDelegate3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 42 SDelegate2::~SDelegate2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 42 SDelegate2::~SDelegate2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 35 SDelegate1::~SDelegate1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 35 SDelegate1::~SDelegate1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 SDelegate0::~SDelegate0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 SDelegate0::~SDelegate0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 21 SInline::~SInline .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 21 SInline::~SInline .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 S::~S .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 S::~S .*(\n|\r\n|\r)*" }
+
+// test1
+// { dg-output "default std::handle_contract_violation called: .*.C 73 G0::G0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 80 G1::G1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 81 G1::~G1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 74 G0::~G0 .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor2.C
new file mode 100644
index 00000000000..ba3b7678ef6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-ctor-dtor2.C
@@ -0,0 +1,35 @@
+// Tests to ensure that an invalid this parm cannot be used in pre on ctors or
+// in post on dtors.
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+struct F0
+{
+  F0() [[ pre: x > 0 ]]; // { dg-error "invalid use of member" }
+  ~F0() [[ post: x > 0 ]]; // { dg-error "invalid use of member" }
+  int x{-1};
+};
+
+struct F1
+{
+  F1() [[ pre: this->x > 0 ]]; // { dg-error "may not be used" }
+  ~F1() [[ post: this->x > 0 ]]; // { dg-error "may not be used" }
+  int x{-1};
+};
+
+struct F2
+{
+  F2()
+    [[ post ret: false ]] // { dg-error "does not return a value" }
+  {
+  }
+  ~F2()
+    [[ post r: false ]] // { dg-error "does not return a value" }
+  {
+  }
+  void f()
+    [[ post r: false ]] // { dg-error "does not return a value" }
+  {
+  }
+};
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-cv1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-cv1.C
new file mode 100644
index 00000000000..8266b4fed8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-cv1.C
@@ -0,0 +1,37 @@
+// Tests to ensure that contracts have a properly cv qualified this
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+struct S
+{
+  int g() const { return x_; }
+  int f() { return x_; }
+
+  void mem_c() const
+    [[ pre: f() ]] // { dg-error "discards qualifiers" }
+  {
+  }
+  void mem_nc()
+    [[ pre: f() ]]
+  {
+  }
+
+  void memc_c() const
+    [[ pre: g() ]]
+  {
+  }
+  void memc_nc()
+    [[ pre: g() ]]
+  {
+  }
+
+  private:
+    int x_{-10};
+};
+
+int main(int, char**)
+{
+  S s;
+  return 0;
+};
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-deduced1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-deduced1.C
new file mode 100644
index 00000000000..e78ee6b6a9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-deduced1.C
@@ -0,0 +1,108 @@
+// Tests to ensure that deduced return types work with postconditions using
+// the return value on defining declarations.
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+auto undeduced(int z)
+{
+  if (!(sizeof(decltype(undeduced(5))) > 4)) // { dg-error "before deduction" }
+    return 5;
+  return 4;
+}
+
+// defining declaration, fine
+auto g0(int a) [[ pre: a < 0 ]] [[ post r: r > 0 ]]
+{
+  return -a * 1.2;
+}
+
+// non defining post using nondeduced identifier, fine
+int g1(int m) [[ post r: r == m ]];
+
+int g1(int n) [[ post s: s == n ]]
+{
+  return -n;
+}
+
+int g2(int z)
+  [[ pre: sizeof(decltype(g2(5))) > 4 ]]; // { dg-error "not declared" }
+
+int g3(int z)
+  [[ pre: sizeof(decltype(g2(5))) > 4 ]]
+{
+  return -z;
+}
+
+// deduced that doesn't use return, good
+auto g4(int m) [[ post: m ]];
+
+auto g4(int m) [[ post: m ]]
+{
+  return -m;
+}
+
+auto g5(int m) [[ pre: m ]];
+
+auto g5(int m) [[ pre: m ]]
+{
+  return -m;
+}
+
+template<typename T>
+auto g6(T t) [[ post r: r == t ]];
+
+template<typename S>
+auto g6(S s) [[ post q: q == s ]]
+{
+  return s;
+}
+
+template<typename T>
+T g7(T t) [[ post r: r == t ]];
+
+template<typename S>
+S g7(S s) [[ post q: q == s ]]
+{
+  return s;
+}
+
+template<typename T>
+auto g8(T t) [[ post r: r == t && sizeof(decltype(::g8(t))) > 2 ]]; // { dg-error "not been declared" }
+
+// This failure is related to the fact that we've invalidated the previous
+// contract. 
+template<typename S>
+auto g8(S s) [[ post q: q == s && sizeof(decltype(::g8(s))) > 2 ]] // { dg-error "mismatched" }
+{
+  return s;
+}
+
+// non defining pre, bad
+auto f0(int z)
+  [[ pre: sizeof(decltype(f0(5))) > 4 ]]; // { dg-error "not declared" }
+
+// defining pre, still ill formed
+auto f1(int z)
+  [[ pre: sizeof(decltype(f1(5))) > 4 ]] // { dg-error "not declared" }
+{
+  return '5';
+}
+
+// undeduced using postcon, OK
+auto f2(int m) [[ post r: r == m ]];
+
+auto f2(int n) [[ post s: s == n ]]
+{
+  return n;
+}
+
+template<typename T>
+void f3(T t) [[ post r: false ]] // { dg-error "function does not return a value" }
+{
+}
+
+int main(int, char**)
+{
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-deduced2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-deduced2.C
new file mode 100644
index 00000000000..da9c019f10a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-deduced2.C
@@ -0,0 +1,84 @@
+// check that contracts work around deduced return types
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+auto g0(int a) [[ pre: a < 0 ]] [[ post r: r > 0 ]]
+{
+  return -a * 1.2;
+}
+
+int g1(int m) [[ post r: r == m ]];
+
+int g1(int n) [[ post s: s == n ]]
+{
+  return -n;
+}
+
+int g2(int z)
+{
+  return -z;
+}
+
+int g3(int z)
+  [[ pre: sizeof(decltype(g2(5))) > 4 ]]
+{
+  return -z;
+}
+
+auto g4(int m) [[ post: m ]];
+
+auto g4(int m) [[ post: m ]]
+{
+  return -m;
+}
+
+auto g5(int m) [[ pre: m ]];
+
+auto g5(int m) [[ pre: m ]]
+{
+  return -m;
+}
+
+template<typename T>
+auto g6(T t) [[ post r: r == t ]];
+
+template<typename S>
+auto g6(S s) [[ post q: q == s ]]
+{
+  return -s;
+}
+
+// template<typename T>
+// T g7(T t) [[ post r: r == t ]];
+
+template<typename S>
+S g7(S s) [[ post q: q == s ]]
+{
+  return -s;
+}
+
+int main(int, char**) {
+  g0(5);
+  g1(6);
+  g2(1);
+  g3(1);
+  g4(0);
+  g5(0);
+  g6(5);
+  g6(5.5);
+  g7(5);
+  g7(6.6);
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 5 g0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 5 g0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 g1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 23 g3 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 30 g4 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 37 g5 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 46 g6<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 46 g6<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 g7<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 g7<double> .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-friend1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-friend1.C
new file mode 100644
index 00000000000..01cebb0c2fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-friend1.C
@@ -0,0 +1,36 @@
+// ensure contracts on friend declarations are a complete class context
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+struct X {
+  friend void fn2(X x);
+  static void fns0(X x) [[ pre: x.a > 0 ]] { }
+  static void fns1(X x) [[ pre: x.a > 0 ]];
+  static void fns2(X x);
+
+  friend void fn(X &x) { x.a = -5; }
+
+private:
+  int a{10};
+};
+
+void fn2(X x) [[ pre: x.a > 0 ]] { }
+void X::fns1(X x) { }
+void X::fns2(X x) [[ pre: x.a > 0 ]] { }
+
+int main(int, char**) {
+  X x;
+  fn(x); // no contract
+
+  fn2(x);
+
+  X::fns0(x);
+  X::fns1(x);
+  X::fns2(x);
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 17 fn2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 X::fns0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 8 X::fns1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 19 X::fns2 .*(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-ft1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-ft1.C
new file mode 100644
index 00000000000..e5d5be7cb6a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-ft1.C
@@ -0,0 +1,14 @@
+// { dg-do compile }
+
+#ifdef __cpp_contracts
+static_assert (false);
+#endif
+
+#ifdef __cpp_contracts_literal_semantics
+static_assert (false);
+#endif
+
+#ifdef __cpp_contracts_roles
+static_assert (false);
+#endif
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-ignore1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-ignore1.C
new file mode 100644
index 00000000000..c8ae6568166
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-ignore1.C
@@ -0,0 +1,30 @@
+// test that ignored contracts do instatiate templates
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+template<typename T>
+int f(T t)
+{
+  return -t;
+}
+
+int dummy()
+{
+  [[ assert ignore: f(1.0) > 0 ]];
+  return -1;
+}
+
+template<>
+int f(double t) // { dg-error "specialization of.*after instantiation" }
+{
+  return -1.0;
+}
+
+int main()
+{
+  dummy();
+  f(1);
+  f(1.0);
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-ignore2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-ignore2.C
new file mode 100644
index 00000000000..5cf800a3559
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-ignore2.C
@@ -0,0 +1,26 @@
+// baseline for testing assert contracts being turned into compile time
+// assumptions; see contracts-assume2 for the assumed case
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+#include <cstdio>
+
+int fun(int x) {
+  [[assert audit: x > 0]];
+  if(x <= 0)
+  {
+    printf("%d: test x<=0 opt out\n", x);
+    return -1;
+  }
+  else
+  {
+    printf("%d: test x>0\n", x);
+    return 0;
+  }
+}
+
+int main(int, char**) {
+  volatile int x = -1;
+  return fun(x);
+}
+
+// { dg-shouldfail "" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-large-return.C b/gcc/testsuite/g++.dg/cpp2a/contracts-large-return.C
new file mode 100644
index 00000000000..ea8e73a387f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-large-return.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+struct Foo
+{
+  int x;
+  bool y;
+  long z[4];
+};
+
+Foo foo() [[ pre: true ]]
+{
+  return {};
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-multiple-inheritance1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-multiple-inheritance1.C
new file mode 100644
index 00000000000..3f2f5edd6ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-multiple-inheritance1.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+struct BaseA {
+  virtual int fun(int n) [[ pre: n > 0 ]] { return -n; }
+};
+
+struct BaseB {
+  virtual int fun(int n) [[ pre: n > 0 ]] { return -n; }
+};
+
+struct Child : public BaseA, BaseB {
+  int fun(int n) [[ pre: n > 0 ]] { return -n; }
+};
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-multiple-inheritance2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-multiple-inheritance2.C
new file mode 100644
index 00000000000..37bdac1d63f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-multiple-inheritance2.C
@@ -0,0 +1,33 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+struct BaseA {
+  virtual int fun(int n) [[ pre: n > 0 ]] { return -n; }
+};
+
+struct BaseB {
+  virtual int fun(int n) [[ pre: n < 0 ]] { return -n; }
+};
+
+struct Child1 : public BaseA, BaseB {
+  int fun(int n) [[ pre: n > 0 ]] { return -n; } // { dg-error "mismatched" }
+};
+
+struct Child2 : public BaseA, BaseB {
+  int fun(int n) [[ pre: n < 0 ]] { return -n; } // { dg-error "mismatched" }
+};
+
+struct Child3 : public BaseA, BaseB {
+  int fun(int n) { return -n; }
+};
+
+struct Child4 : public BaseA {
+  int fun(int n);
+};
+
+int Child4::fun(int n)
+  [[ pre: n != 0 ]] // { dg-error "mismatched" }
+{
+  return -n;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-nested-class1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-nested-class1.C
new file mode 100644
index 00000000000..e6c362ab2a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-nested-class1.C
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+void gfn3(int n) [[ pre: n > 0 ]];
+
+struct Outer {
+  struct Inner {
+    void fn(int n) [[ pre: n > 0 && bob > 1 ]];
+    void fn2(int n) [[ pre: n > 0 && bob > 1 ]];
+  };
+
+  void fn(int m) [[ pre: m > 1 ]];
+  friend void Inner::fn(int n) [[ pre: n > 0 && bob > 1 ]]; // { dg-error "not declared" }
+
+  // FIXME: These functions are merged together with no diagnostic. We get an
+  // error about 'p' not being declared because the contracts haven't been
+  // unified or remapped.
+  friend void gfn(int p) [[ pre: p > 0 ]];
+  friend void gfn(int q) [[ pre: q > 1 ]]; // { dg-error "mismatched contract" }
+
+  // This should be okay.
+  friend void gfn2(int q);
+  friend void gfn2(int p) [[ pre: p > 0 ]] { }
+
+  static int bob;
+};
+int Outer::bob{-1};
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-nested-class2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-nested-class2.C
new file mode 100644
index 00000000000..43e75edbef8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-nested-class2.C
@@ -0,0 +1,40 @@
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+void gfn3(int n) [[ pre: n > 0 ]];
+
+struct Outer {
+  struct Inner {
+    void fn(int n) [[ pre: n > 0 && bob > 1 ]];
+  };
+
+  void fn(int m) [[ pre: m > 1 ]];
+
+  friend void gfn1(int q);
+  friend void gfn1(int p) [[ pre: p > 0 ]] { }
+
+  friend void gfn2(int q, Outer *);
+  friend void gfn2(int p, Outer *) [[ pre: p > 0 ]] { }
+
+  friend void gfn3(int n);
+
+  static int bob;
+};
+int Outer::bob{-1};
+
+void Outer::Inner::fn(int x) { }
+void Outer::fn(int y) { }
+
+void gfn3(int n) { }
+void gfn1(int q);
+
+int main(int, char **) {
+  Outer::Inner in;
+  in.fn(-5);
+  Outer out;
+  out.fn(-6);
+  gfn1(-7);
+  gfn2(-8, &out);
+  gfn3(-9);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-override.C b/gcc/testsuite/g++.dg/cpp2a/contracts-override.C
new file mode 100644
index 00000000000..f96aa988e0f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-override.C
@@ -0,0 +1,43 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+struct Foo {
+  virtual int f0(int n) [[ pre: false ]] { return n; }
+  virtual int f1(int n) [[ pre: false ]] { return n; }
+  virtual int f2(int n) [[ pre: false ]] { return n; }
+  virtual int f3(int n) [[ pre: false ]] { return n; }
+  virtual int f4(int n) [[ pre: false ]] { return n; }
+  virtual int f5(int n) [[ pre: false ]] { return n; }
+  virtual int f6(int n) [[ pre: false ]] { return n; }
+  virtual int f7(int n) [[ pre: false ]] { return n; }
+  virtual int f8(int n) [[ pre: false ]] { return n; }
+  virtual int f9(int n) [[ pre: false ]] { return n; }
+  virtual int f10(int n) [[ pre: false ]] { return n; }
+  virtual int f11(int n) [[ pre: n > 0 ]] [[ pre: n > 1 ]] { return n; }
+  virtual int f12(int n) [[ pre: n > 0 ]] [[ pre: n > 1 ]] { return n; }
+};
+
+struct Bar : Foo {
+  [[ pre: n > -1 ]] int f0(int n = 0) override { return -n; } // { dg-error "contracts must appertain" }
+  int [[ pre: n > -2 ]] f1(int n = 0) override { return -n; } // { dg-error "contracts must appertain" }
+  int f2 [[ pre: n > -3 ]] (int n = 0) override { return -n; } // { dg-error "contracts must appertain" }
+  int f4([[ pre: n > -4 ]] int n = 0) override { return -n; } // { dg-error "contracts must appertain" }
+  int f5(int [[ pre: n > -5 ]] n = 0) override { return -n; } // { dg-error "contracts must appertain" }
+  int f6(int n [[ pre: n > -6 ]] = 0) override { return -n; } // { dg-error "contracts must appertain" }
+  int f7(int n = [[ pre: n > -7 ]] 0) override { return -n; }
+  // { dg-error "expected identifier" "" { target *-*-* } .-1 }
+  // { dg-error "expected .\{. before numeric" "" { target *-*-* } .-2 }
+  // { dg-error "invalid user-defined conversion" "" { target *-*-* } .-3 }
+  // { dg-error "expected .,." "" { target *-*-* } .-4 }
+  int f8(int n = 0 [[ pre: n > -8 ]]) override { return -n; }
+  // { dg-error "shall only introduce an attribute" "" { target *-*-* } .-1 }
+  int f9(int n = 0) [[ pre: n > -9 ]] override { return -n; } // { dg-error "mismatched contract" }
+
+  // The grammar doesn't appear to permit contracts after the virt-specifiers
+  // but the parser will happily add these to an attribute list that is not
+  // owned by the function declarator.
+  int f10(int n = 0) override [[ pre: n > -10 ]] { return -n; } // { dg-error "contracts must appertain" }
+  int f11(int n) [[ pre: n > 1 ]] override [[ pre: n > 0 ]] { return -n; } // { dg-error "contracts must appertain" }
+  int f12(int n) [[ pre: n > 0 ]] override [[ pre: n > 1 ]] { return -n; } // { dg-error "contracts must appertain" }
+};
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-post1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-post1.C
new file mode 100644
index 00000000000..451760ea822
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-post1.C
@@ -0,0 +1,74 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+int f1(int n)
+  [[pre: n >= 0]]
+  [[post r: r >= 0]]
+  [[post r: !(r < 0)]]
+{
+  return n;
+}
+
+int f2(int n)
+  [[post: true]]
+{
+  return 0;
+}
+
+int f3(int n)
+  [[post r: r >= n]]
+{
+  return n + 1;
+}
+
+int f4(int n)
+  [[post: x > 0]] // { dg-error "not declared" }
+{
+  return 0;
+}
+
+void f5()
+  [[post: true]]
+{ }
+
+void f6()
+  [[post r: true]] // { dg-error "function does not return a value" }
+{ }
+
+int f7(int n)
+  [[post: n > 0]]
+{
+  return x; // { dg-error "not declared" }
+}
+
+void f8(int n)
+  [[post: n > 0]]
+{
+  return;
+}
+
+void f9(int n)
+  [[post: n > 0]]
+{
+  return n; // { dg-error "return-statement with a value" }
+}
+
+int f10(int n)
+  [[post: n > 0]]
+{
+  return; // { dg-error "return-statement with no value" }
+}
+
+void f11()
+  [[post: true]]
+{
+  constexpr int n = 0;
+  return n; // { dg-error "return-statement with a value" }
+}
+
+int f12()
+  [[post: true]]
+{
+  return; // { dg-error "return-statement with no value" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-post2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-post2.C
new file mode 100644
index 00000000000..7665f829107
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-post2.C
@@ -0,0 +1,13 @@
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+
+int f1(int n)
+  [[post r: r == n]]
+{
+  return n;
+}
+
+int main()
+{
+  f1(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-post3.C b/gcc/testsuite/g++.dg/cpp2a/contracts-post3.C
new file mode 100644
index 00000000000..9f1dffd8f6a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-post3.C
@@ -0,0 +1,15 @@
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+// { dg-shouldfail "assert violation" }
+// { dg-output "default std::handle_contract_violation called" }
+
+int f1(int n)
+  [[post r: r > n]]
+{
+  return n;
+}
+
+int main()
+{
+  f1(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-post4.C b/gcc/testsuite/g++.dg/cpp2a/contracts-post4.C
new file mode 100644
index 00000000000..af770c3dc94
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-post4.C
@@ -0,0 +1,36 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+struct S
+{
+  S() [[post: n == 0]]
+    : n(0)
+  { }
+
+  ~S() [[post: true]]
+  { }
+
+  int f1()
+    [[post r: n == r]]
+  {
+    return n;
+  }
+
+  int f2()
+    [[post r: r == x]] // { dg-error "not declared" }
+  {
+    return n;
+  }
+
+  void f3()
+    [[post r: n]] // { dg-error "does not return a value" }
+  {
+  }
+
+  int n = 0;
+};
+
+int main()
+{
+  // f1(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-post5.C b/gcc/testsuite/g++.dg/cpp2a/contracts-post5.C
new file mode 100644
index 00000000000..c9127fb2cc9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-post5.C
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+// Tests for function templates
+
+template<typename T>
+T f1(T n)
+  [[pre: n >= 0]]
+  [[post r: r >= 0]]
+  [[post r: !(r < 0)]]
+{
+  return n;
+}
+
+
+void driver()
+{
+  f1(0);
+}
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-post6.C b/gcc/testsuite/g++.dg/cpp2a/contracts-post6.C
new file mode 100644
index 00000000000..dacb97b9ebf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-post6.C
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+// Test for class members
+
+template<typename T>
+struct S
+{
+  S(T n)
+    [[post: true]]
+    : n(n)
+  { }
+
+  T f1(T n)
+    [[pre: n >= 0]]
+    [[post r: r >= 0]]
+    [[post r: !(r < 0)]]
+  {
+    return n;
+  }
+
+  T n;
+};
+
+
+void driver()
+{
+  S<int> s1(0);
+}
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre1.C
new file mode 100644
index 00000000000..908103cde1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre1.C
@@ -0,0 +1,36 @@
+// generic pre contract parsing checks
+//   check omitted, 'default', 'audit', and 'axiom' contract levels parse
+//   ensure that an invalid contrcat level 'off' errors
+//   ensure that a predicate referencing an undefined variable errors
+//   ensure that a missing colon after contract level errors
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+void f1(int x) [[ pre: x >= 0 ]] { }
+void f2(int x) [[ pre default: x >= 0 ]] { }
+void f3(int x) [[ pre audit: x >= 0 ]] { }
+void f4(int x) [[ pre axiom: x >= 0 ]] { }
+
+void finvalid(int x) [[ pre invalid: x >= 0 ]] { } // { dg-error "expected contract level" }
+void fundeclared() [[ pre: x >= 0 ]] { } // { dg-error ".x. was not declared in this scope" }
+void fmissingcolon(int x) [[ pre default x == 0]] { } // { dg-error "expected .:. before .x." }
+
+int Z;
+void (*fp1)(int x) [[ pre: Z > 0 ]]; // { dg-error "contracts must appertain" }
+void (*fp2 [[ pre: Z > 0 ]])(int x); // { dg-error "contracts must appertain" }
+typedef void (*fp3)(int x) [[ pre: Z > 0 ]]; // { dg-error "contracts must appertain" }
+typedef void (*fp4 [[ pre: Z > 0 ]])(int x); // { dg-error "contracts must appertain" }
+fp3 fn5(int a) [[ pre: a > 0 ]]; // { dg-bogus "contracts must appertain" }
+
+int xyz;
+[[ pre: xyz ]] struct Bar; // { dg-error "contracts must appertain" }
+// { dg-warning "attribute ignored" "" { target *-*-* } .-1 }
+struct [[ pre: xyz ]] Bar; // { dg-error "contracts must appertain" }
+struct Bar [[ pre: xyz ]]; // { dg-error "contracts must appertain" }
+struct Zoo {} x [[ pre: xyz ]]; // { dg-error "contracts must appertain" }
+
+void f6(int x) [[ pre: x > 0 ; // { dg-error "expected .]." }
+void f7(int x) [[ pre: x > 0 ]; // { dg-error "expected .]." }
+void f8(int x) [[ pre: x > 0 { }; // { dg-error "expected .]." }
+void f9(int x) [[ pre: x > 0 ] { }; // { dg-error "expected .]." }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre10.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre10.C
new file mode 100644
index 00000000000..877e9ada404
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre10.C
@@ -0,0 +1,190 @@
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+struct M
+{
+  template<typename T>
+  int f(int a) [[ pre: a > 0 ]];
+
+  template<typename T>
+  int g(int a) [[ pre: a > 0 ]]
+  {
+    return -a;
+  }
+
+  template<typename T>
+  int f_arg(T a) [[ pre: a > 0 ]];
+
+  template<typename T>
+  int g_arg(T a) [[ pre: a > 0 ]]
+  {
+    return (int)-a;
+  }
+
+  template<typename T>
+  T f_ret(int a) [[ pre: a > 0 ]];
+
+  template<typename T>
+  T g_ret(int a) [[ pre: a > 0 ]]
+  {
+    return -a * 1.5;
+  }
+};
+
+template<typename T>
+int M::f(int a)
+{
+  return -a;
+}
+
+template<typename T>
+int M::f_arg(T a)
+{
+  return (int)-a;
+}
+
+template<typename T>
+T M::f_ret(int a)
+{
+  return -a * (T)1.5;
+}
+
+template<typename T>
+struct S
+{
+  template<typename Q>
+  int f(int a) [[ pre: a > 0 ]];
+
+  template<typename Q>
+  int g(int a) [[ pre: a > 0 ]]
+  {
+    return -a;
+  }
+};
+
+template<typename T>
+template<typename Q>
+int S<T>::f(int a)
+{
+  return -a;
+}
+
+#include <cstdio>
+int main(int, char**)
+{
+  {
+    M m;
+    printf ("=================================\n");
+    printf ("m.f<int>(-10): %d\n", m.f<int>(-10));
+    printf ("m.f<double>(-11.5): %d\n", m.f<double>(-11.5));
+    printf ("m.f<int>(10): %d\n", m.f<int>(10));
+    printf ("m.f<double>(11.5): %d\n", m.f<double>(11.5));
+
+    printf ("=================================\n");
+    printf ("m.g<int>(-10): %d\n", m.g<int>(-10));
+    printf ("m.g<double>(-11.5): %d\n", m.g<double>(-11.5));
+    printf ("m.g<int>(10): %d\n", m.g<int>(10));
+    printf ("m.g<double>(11.5): %d\n", m.g<double>(11.5));
+
+    printf ("=================================\n");
+    printf ("m.f_arg(-10): %d\n", m.f_arg(-10));
+    printf ("m.f_arg(-11.5): %d\n", m.f_arg(-11.5));
+    printf ("m.f_arg(10): %d\n", m.f_arg(10));
+    printf ("m.f_arg(11.5): %d\n", m.f_arg(11.5));
+
+    printf ("=================================\n");
+    printf ("m.g_arg(-10): %d\n", m.g_arg(-10));
+    printf ("m.g_arg(-11.5): %d\n", m.g_arg(-11.5));
+    printf ("m.g_arg(10): %d\n", m.g_arg(10));
+    printf ("m.g_arg(11.5): %d\n", m.g_arg(11.5));
+
+    printf ("=================================\n");
+    printf ("m.f_ret<int>(-10): %d\n", m.f_ret<int>(-10));
+    printf ("m.f_ret<double>(-11.5): %f\n", m.f_ret<double>(-11.5));
+    printf ("m.f_ret<int>(10): %d\n", m.f_ret<int>(10));
+    printf ("m.f_ret<double>(11.5): %f\n", m.f_ret<double>(11.5));
+
+    printf ("=================================\n");
+    printf ("m.g_ret<int>(-10): %d\n", m.g_ret<int>(-10));
+    printf ("m.g_ret<double>(-11.5): %f\n", m.g_ret<double>(-11.5));
+    printf ("m.g_ret<int>(10): %d\n", m.g_ret<int>(10));
+    printf ("m.g_ret<double>(11.5): %f\n", m.g_ret<double>(11.5));
+  }
+
+  {
+    S<int> s;
+    printf ("=================================\n");
+    s.f<int>(-10);
+
+    s.f<double>(-10);
+
+    printf ("=================================\n");
+    s.g<int>(-10);
+
+    s.g<double>(-10);
+  }
+
+  {
+    S<double> s;
+    printf ("=================================\n");
+    s.f<int>(-10);
+
+    s.f<double>(-10);
+
+    printf ("=================================\n");
+    s.g<int>(-10);
+
+    s.g<double>(-10);
+  }
+
+  return 0;
+}
+
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 M::f<int> .*(\n|\r\n|\r)*" }
+// { dg-output "m.f<int>.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 M::f<double> .*(\n|\r\n|\r)*" }
+// { dg-output "m.f<double>.-11.5.: 11(\n|\r\n|\r)*" }
+// { dg-output "m.f<int>.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "m.f<double>.11.5.: -11(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 M::g<int> .*(\n|\r\n|\r)*" }
+// { dg-output "m.g<int>.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 M::g<double> .*(\n|\r\n|\r)*" }
+// { dg-output "m.g<double>.-11.5.: 11(\n|\r\n|\r)*" }
+// { dg-output "m.g<int>.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "m.g<double>.11.5.: -11(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 16 M::f_arg<int> .*(\n|\r\n|\r)*" }
+// { dg-output "m.f_arg.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 16 M::f_arg<double> .*(\n|\r\n|\r)*" }
+// { dg-output "m.f_arg.-11.5.: 11(\n|\r\n|\r)*" }
+// { dg-output "m.f_arg.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "m.f_arg.11.5.: -11(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 19 M::g_arg<int> .*(\n|\r\n|\r)*" }
+// { dg-output "m.g_arg.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 19 M::g_arg<double> .*(\n|\r\n|\r)*" }
+// { dg-output "m.g_arg.-11.5.: 11(\n|\r\n|\r)*" }
+// { dg-output "m.g_arg.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "m.g_arg.11.5.: -11(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 25 M::f_ret<int> .*(\n|\r\n|\r)*" }
+// { dg-output "m.f_ret<int>.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 25 M::f_ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "m.f_ret<double>.-11.5.: 16.500000(\n|\r\n|\r)*" }
+// { dg-output "m.f_ret<int>.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "m.f_ret<double>.11.5.: -16.500000(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 M::g_ret<int> .*(\n|\r\n|\r)*" }
+// { dg-output "m.g_ret<int>.-10.: 15(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 M::g_ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "m.g_ret<double>.-11.5.: 16.500000(\n|\r\n|\r)*" }
+// { dg-output "m.g_ret<int>.10.: -15(\n|\r\n|\r)*" }
+// { dg-output "m.g_ret<double>.11.5.: -16.500000(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 59 S<int>::g<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 59 S<int>::g<double> .*(\n|\r\n|\r)*" }
+// { dg-output "=================================(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 59 S<double>::g<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 59 S<double>::g<double> .*(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre2.C
new file mode 100644
index 00000000000..4fe2f9d0192
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre2.C
@@ -0,0 +1,212 @@
+// basic test to ensure pre contracts work for free functions
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+namespace nullary
+{
+  int x = 10;
+  int y = 10;
+
+  void fun()
+    [[ pre: x < 0 ]]
+  {
+    printf("fun::x: %d\n", x);
+  }
+
+  void fun2()
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+  {
+    printf("fun2::x: %d fun2::y: %d\n", x, y);
+  }
+
+  void funend()
+    [[ pre: x < 0 ]];
+}
+
+namespace nonvoid
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  void vfun()
+    [[ pre: x < 0 ]]
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+  int fun()
+    [[ pre: x < 0 ]]
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double fun2()
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+
+  S funend()
+    [[ pre: x < 0 ]];
+}
+
+namespace nonnullary
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  void vfun(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+  int fun(int m, double n)
+    [[ pre: x < 0 ]]
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double fun2(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]]
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+
+  S funend(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]];
+}
+
+int main(int, char**) {
+  // nullary void
+  {
+    nullary::fun();
+    nullary::fun2();
+    nullary::funend();
+  }
+
+  // nullary non void
+  {
+    nonvoid::vfun();
+
+    int f = 13;
+    f = nonvoid::fun();
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = nonvoid::fun2();
+    printf("main::d: %f\n", d);
+    nonvoid::S s = nonvoid::funend();
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+
+  // non-nullary non-void
+  {
+    int x = 11;
+    double y = 11.5;
+
+    nonnullary::vfun(x, y);
+
+    int f = 13;
+    f = nonnullary::fun(x, y);
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = nonnullary::fun2(x, y);
+    printf("main::d: %f\n", d);
+    nonnullary::S s = nonnullary::funend(x, y);
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+  return 0;
+}
+
+namespace nullary
+{
+  void funend()
+    [[ pre: x < 0 ]]
+  {
+    printf("funend::x: %d\n", x);
+  }
+}
+
+namespace nonvoid
+{
+  S funend()
+    [[ pre: x < 0 ]]
+  {
+    printf("funend::x: %d\n", x);
+    S s;
+    s.z = true;
+    return s;
+  }
+}
+
+namespace nonnullary
+{
+  S funend(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("funend::x: %d\n", x);
+    S s;
+    s.z = true;
+    return s;
+  }
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 12 nullary::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 18 nullary::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 19 nullary::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 146 nullary::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 nonvoid::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 45 nonvoid::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 52 nonvoid::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 53 nonvoid::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 155 nonvoid::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 74 nonnullary::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 75 nonnullary::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 81 nonnullary::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 88 nonnullary::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 89 nonnullary::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 90 nonnullary::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 91 nonnullary::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 167 nonnullary::funend .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 168 nonnullary::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre2a1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre2a1.C
new file mode 100644
index 00000000000..26167492b97
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre2a1.C
@@ -0,0 +1,33 @@
+// ensure the feature test macros are defined pre c++20 while we still support
+// -fcontracts independent of std version
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fcontracts" }
+
+static_assert (__cpp_contracts >= 201906, "__cpp_contracts");
+static_assert (__cpp_contracts_literal_semantics >= 201906, "__cpp_contracts_literal_semantics");
+static_assert (__cpp_contracts_roles >= 201906, "__cpp_contracts_roles");
+
+int main()
+{
+  int x;
+
+  [[assert: x >= 0]];
+  [[assert default: x < 0]];
+  [[assert audit: x == 0]];
+  [[assert axiom: x == 1]];
+
+  [[assert: x > 0 ? true : false]];
+  [[assert: x < 0 ? true : false]];
+
+  [[assert ignore: x >= 0]];
+  [[assert assume: x >= 0]];
+  [[assert check_never_continue: x >= 0]];
+  [[assert check_maybe_continue: x >= 0]];
+
+  [[assert %default: x >= 0]];
+  [[assert default %default: x < 0]];
+  [[assert audit %default: x == 0]];
+  [[assert axiom %default: x == 1]];
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre2a2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre2a2.C
new file mode 100644
index 00000000000..db9a0c37aa0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre2a2.C
@@ -0,0 +1,22 @@
+// basic test to ensure contracts work pre-c++2a
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-fcontracts -fcontract-continuation-mode=on" }
+
+int f(int n)
+  [[ pre: n > 0 ]]
+  [[ post r: r < 0 ]]
+{
+  [[ assert: n > 0 ]];
+  return -n;
+}
+
+int main()
+{
+  f(-5);
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 6 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 9 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre3.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre3.C
new file mode 100644
index 00000000000..1c4e3a98e63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre3.C
@@ -0,0 +1,525 @@
+// tests to ensure pre contracts work on member functions
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+namespace member
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  struct T1
+  {
+    void vfun(int m, double n)
+      [[ pre: x < 0 ]]
+      [[ pre: m < 0 ]];
+
+    int fun(int m, double n)
+      [[ pre: x < 0 ]];
+
+    double fun2(int m, double n)
+      [[ pre: x < 0 ]]
+      [[ pre: y < 0 ]]
+      [[ pre: m < 0 ]]
+      [[ pre: n < 0 ]];
+
+    S funend(int m, double n)
+      [[ pre: x < 0 ]]
+      [[ pre: m < 0 ]];
+  };
+
+  void T1::vfun(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+
+  int T1::fun(int m, double n)
+    [[ pre: x < 0 ]]
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double T1::fun2(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]]
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+}
+
+namespace special
+{
+  struct T1
+  {
+    T1(int m, int n)
+      [[ pre: m < 0 ]]
+      [[ pre: n < 0 ]];
+
+    int operator+(int m)
+      [[ pre: m > 0 ]]
+      [[ pre: v > 0 ]];
+
+    int operator-(int m)
+      [[ pre: m > 0 ]]
+      [[ pre: v > 0 ]];
+
+    ~T1()
+      [[ pre: v > 0 ]];
+
+    int v{-10};
+  };
+
+  T1::T1(int m, int n)
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]]
+    : v{-m * n}
+  {
+  }
+
+  int T1::operator+(int m)
+    [[ pre: m > 0 ]]
+    [[ pre: v > 0 ]]
+  {
+    return v + m;
+  }
+
+  int T1::operator-(int m)
+    [[ pre: m > 0 ]]
+    [[ pre: v > 0 ]]
+  {
+    return v - m;
+  }
+
+  T1::~T1()
+    [[ pre: v > 0 ]]
+  {
+  }
+
+  struct T2
+  {
+    T2(int m, int n)
+      [[ pre: m < 0 ]]
+      [[ pre: n < 0 ]]
+      : v{-m * n}
+    {
+    }
+
+    int operator+(int m)
+      [[ pre: m > 0 ]]
+      [[ pre: v > 0 ]]
+    {
+      return v + m;
+    }
+
+    int operator-(int m)
+      [[ pre: m > 0 ]]
+      [[ pre: v > 0 ]]
+    {
+      return v - m;
+    }
+
+    ~T2()
+      [[ pre: v > 0 ]]
+    {
+    }
+
+    int v{-10};
+  };
+
+  struct TC : T1
+  {
+    TC(int m, int n)
+      [[ pre: m < -1 ]]
+      [[ pre: n < -1 ]]
+      : T1{m, n}
+    {
+    }
+
+    ~TC()
+      [[ pre: vc < 0 ]]
+    {
+    }
+
+    TC(int a)
+      [[ pre: a < 0 ]]
+      : TC{a, a}
+    {
+    }
+
+    int vc{10};
+  };
+
+  void test()
+  {
+    T1 t1{10, 20};
+    int a = t1 - -5;
+    int b = t1 + -5;
+    printf("==========\n");
+
+    T2 t2{10, 20};
+    int k = t2 - -5;
+    int j = t2 + -5;
+    printf("==========\n");
+
+    TC tc{10, 20};
+    printf("==========\n");
+
+    TC tc2{10};
+    printf("==========\n");
+  }
+}
+
+namespace virt
+{
+  struct T1
+  {
+    virtual int fun(int m, int n)
+      [[ pre: m > 0 ]]
+      [[ pre: n > 0 ]]
+      [[ pre: v > 0 ]];
+    int v{-10};
+  };
+
+  int T1::fun(int m, int n)
+    [[ pre: m > 0 ]]
+    [[ pre: n > 0 ]]
+    [[ pre: v > 0 ]]
+  {
+    printf("T1::fun::m: %d, T1::fun::n: %d, T1::v: %d\n", m, n, v);
+    return m * n * v;
+  }
+
+  struct T2 : T1
+  {
+  };
+
+  struct T3 : T2
+  {
+    virtual int fun(int m, int n)
+      [[ pre: m > 0 ]]
+      [[ pre: n > 0 ]]
+      [[ pre: v > 0 ]]
+      override
+    {
+      printf("T3::fun::m: %d, T3::fun::n: %d, T3::v: %d\n", m, n, v);
+      return m * n * v;
+    }
+  };
+
+  struct T3b : T2
+  {
+    virtual int fun(int m, int n)
+      [[ pre: m > 0 ]]
+      [[ pre: n > 0 ]]
+      [[ pre: v > 0 ]]
+      override;
+
+    int p(int a)
+      [[ pre: a > 0 ]]
+      [[ pre: v > 0 ]];
+
+    int u(int a)
+      [[ pre: a > 0 ]]
+      [[ pre: z > 0 ]];
+
+    int n(int a)
+      [[ pre: a > 0 ]];
+
+    static int Sn(int a)
+      [[ pre: a > 0 ]];
+
+    int z{-10};
+  };
+
+  int T3b::fun(int m, int n)
+    [[ pre: m > 0 ]]
+    [[ pre: n > 0 ]]
+    [[ pre: v > 0 ]]
+  {
+    printf("T3b::fun::m: %d, T3b::fun::n: %d, T3b::v: %d\n", m, n, v);
+    return m * n * v;
+  }
+
+  int T3b::p(int a)
+    [[ pre: a > 0 ]]
+    [[ pre: v > 0 ]]
+  {
+    printf("T3b::p: a: %d, v: %d\n", a, v);
+    return a * v;
+  }
+
+  int T3b::u(int a)
+    [[ pre: a > 0 ]]
+    [[ pre: z > 0 ]]
+  {
+    printf("T3b::u: a: %d, z: %d\n", a, z);
+    return a * z;
+  }
+
+  int T3b::n(int a)
+    [[ pre: a > 0 ]]
+  {
+    printf("T3b::n: a: %d\n", a);
+    return a;
+  }
+
+  int T3b::Sn(int a)
+    [[ pre: a > 0 ]]
+  {
+    printf("T3b::Sn: a: %d\n", a);
+    return a;
+  }
+
+  struct T3c : T2
+  {
+    int fun(int m, int n)
+      [[ pre: m > 0 ]]
+      [[ pre: n > 0 ]]
+      [[ pre: v > 0 ]]
+    {
+      printf("T3c::fun::m: %d, T3c::fun::n: %d, T3c::v: %d\n", m, n, v);
+      return m * n * v;
+    }
+
+    int p(int a)
+      [[ pre: a > 0 ]]
+      [[ pre: v > 0 ]]
+    {
+      printf("T3c::p: a: %d, v: %d\n", a, v);
+      return a * v;
+    }
+
+    int u(int a)
+      [[ pre: a > 0 ]]
+      [[ pre: z > 0 ]]
+    {
+      printf("T3c::u: a: %d, z: %d\n", a, z);
+      return a * z;
+    }
+
+    int n(int a)
+      [[ pre: a > 0 ]]
+    {
+      printf("T3c::n: a: %d\n", a);
+      return a;
+    }
+
+    static int Sn(int a)
+      [[ pre: a > 0 ]]
+    {
+      printf("T3c::Sn: a: %d\n", a);
+      return a;
+    }
+
+    int z{-10};
+  };
+
+  void t(const char *kind, T1 *t)
+  {
+    printf("=================\n%s:\n", kind);
+    t->fun(-1, -2);
+  }
+
+  void test()
+  {
+    T1 t1;
+    t1.fun(-10, -20);
+
+    T2 t2;
+    t2.fun(-10, -20);
+
+    T3 t3;
+    t3.fun(-10, -20);
+
+    T3b t3b;
+    t3b.fun(-10, -20);
+
+    T3c t3c;
+    t3c.fun(-10, -20);
+
+    t("T1", &t1);
+    t("T2", &t2);
+    t("T3", &t3);
+    t("T3b", &t3b);
+    t("T3c", &t3c);
+
+    printf("=============\n");
+    t3b.p(-3);
+    t3b.u(-3);
+    t3b.n(-3);
+    T3b::Sn(-3);
+
+    printf("=============\n");
+    t3c.p(-3);
+    t3c.u(-3);
+    t3c.n(-3);
+    T3c::Sn(-3);
+  }
+}
+
+int main(int, char**) 
+{
+  // ordinary member functions
+  {
+    int x = 11;
+    double y = 11.5;
+    member::T1 t1;
+    t1.vfun(x, y);
+
+    int f = 13;
+    f = t1.fun(x, y);
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = t1.fun2(x, y);
+    printf("main::d: %f\n", d);
+    member::S s = t1.funend(x, y);
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+
+  special::test();
+  virt::test();
+  return 0;
+}
+
+member::S member::T1::funend(int m, double n)
+  [[ pre: x < 0 ]]
+  [[ pre: m < 0 ]]
+{
+  printf("funend::x: %d\n", x);
+  S s;
+  s.z = true;
+  return s;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 37 member::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 member::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 45 member::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 52 member::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 53 member::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 54 member::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 55 member::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 397 member::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 398 member::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 85 special::T1::T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 86 special::T1::T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 99 special::T1::operator- .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 100 special::T1::operator- .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 92 special::T1::operator. .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 93 special::T1::operator. .*(\n|\r\n|\r)*" }
+// { dg-output "==========(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 113 special::T2::T2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 114 special::T2::T2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 127 special::T2::operator- .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 128 special::T2::operator- .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 120 special::T2::operator. .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 121 special::T2::operator. .*(\n|\r\n|\r)*" }
+// { dg-output "==========(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 144 special::TC::TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 145 special::TC::TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 85 special::T1::T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 86 special::T1::T1 .*(\n|\r\n|\r)*" }
+// { dg-output "==========(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 156 special::TC::TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 144 special::TC::TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 145 special::TC::TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 85 special::T1::T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 86 special::T1::T1 .*(\n|\r\n|\r)*" }
+// { dg-output "==========(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 151 special::TC::~TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 106 special::T1::~T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 151 special::TC::~TC .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 106 special::T1::~T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 134 special::T2::~T2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 106 special::T1::~T1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 196 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 197 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 198 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T1::fun::m: -10, T1::fun::n: -20, T1::v: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 196 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 197 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 198 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T1::fun::m: -10, T1::fun::n: -20, T1::v: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 211 virt::T3::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 212 virt::T3::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 213 virt::T3::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T3::fun::m: -10, T3::fun::n: -20, T3::v: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 247 virt::T3b::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 248 virt::T3b::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 249 virt::T3b::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T3b::fun::m: -10, T3b::fun::n: -20, T3b::v: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 288 virt::T3c::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 289 virt::T3c::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 290 virt::T3c::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T3c::fun::m: -10, T3c::fun::n: -20, T3c::v: -10(\n|\r\n|\r)*" }
+// { dg-output "=================(\n|\r\n|\r)*" }
+// { dg-output "T1:(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 196 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 197 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 198 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T1::fun::m: -1, T1::fun::n: -2, T1::v: -10(\n|\r\n|\r)*" }
+// { dg-output "=================(\n|\r\n|\r)*" }
+// { dg-output "T2:(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 196 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 197 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 198 virt::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T1::fun::m: -1, T1::fun::n: -2, T1::v: -10(\n|\r\n|\r)*" }
+// { dg-output "=================(\n|\r\n|\r)*" }
+// { dg-output "T3:(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 211 virt::T3::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 212 virt::T3::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 213 virt::T3::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T3::fun::m: -1, T3::fun::n: -2, T3::v: -10(\n|\r\n|\r)*" }
+// { dg-output "=================(\n|\r\n|\r)*" }
+// { dg-output "T3b:(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 247 virt::T3b::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 248 virt::T3b::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 249 virt::T3b::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T3b::fun::m: -1, T3b::fun::n: -2, T3b::v: -10(\n|\r\n|\r)*" }
+// { dg-output "=================(\n|\r\n|\r)*" }
+// { dg-output "T3c:(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 288 virt::T3c::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 289 virt::T3c::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 290 virt::T3c::fun .*(\n|\r\n|\r)*" }
+// { dg-output "T3c::fun::m: -1, T3c::fun::n: -2, T3c::v: -10(\n|\r\n|\r)*" }
+// { dg-output "=============(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 256 virt::T3b::p .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 257 virt::T3b::p .*(\n|\r\n|\r)*" }
+// { dg-output "T3b::p: a: -3, v: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 264 virt::T3b::u .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 265 virt::T3b::u .*(\n|\r\n|\r)*" }
+// { dg-output "T3b::u: a: -3, z: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 272 virt::T3b::n .*(\n|\r\n|\r)*" }
+// { dg-output "T3b::n: a: -3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 279 virt::T3b::Sn .*(\n|\r\n|\r)*" }
+// { dg-output "T3b::Sn: a: -3(\n|\r\n|\r)*" }
+// { dg-output "=============(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 297 virt::T3c::p .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 298 virt::T3c::p .*(\n|\r\n|\r)*" }
+// { dg-output "T3c::p: a: -3, v: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 305 virt::T3c::u .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 306 virt::T3c::u .*(\n|\r\n|\r)*" }
+// { dg-output "T3c::u: a: -3, z: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 313 virt::T3c::n .*(\n|\r\n|\r)*" }
+// { dg-output "T3c::n: a: -3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 320 virt::T3c::Sn .*(\n|\r\n|\r)*" }
+// { dg-output "T3c::Sn: a: -3(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre4.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre4.C
new file mode 100644
index 00000000000..16189cdce9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre4.C
@@ -0,0 +1,92 @@
+// test that contracts on overriding functions are found correctly
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+struct Base
+{
+  virtual int f(int a) [[ pre: a > 0 ]];
+};
+
+int Base::f(int a)
+{
+  return a + 10;
+}
+
+// inherits original
+struct Child0 : Base
+{
+};
+
+// defined out of line, explicit override
+struct Child1 : Base
+{
+  virtual int f(int a) override;
+};
+
+int Child1::f(int a)
+{
+  return a + 20;
+}
+
+// defined out of line
+struct Child2 : Base
+{
+  int f(int a);
+};
+
+int Child2::f(int a)
+{
+  return a + 30;
+}
+
+// defined inline, explicitly override
+struct Child3 : Base
+{
+  virtual int f(int a) override
+  {
+    return a + 40;
+  }
+};
+
+// defined inline
+struct Child4 : Base
+{
+  int f(int a)
+  {
+    return a + 50;
+  }
+};
+
+#include <cstdio>
+int main(int, char**)
+{
+  Base b;
+  Child0 c0;
+  Child1 c1;
+  Child2 c2;
+  Child3 c3;
+  Child4 c4;
+
+  printf("Base: %d\n", b.f(-10));
+  printf("Child0: %d\n", c0.f(-10));
+  printf("Child1: %d\n", c1.f(-10));
+  printf("Child2: %d\n", c2.f(-10));
+  printf("Child3: %d\n", c3.f(-10));
+  printf("Child4: %d\n", c4.f(-10));
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 7 Base::f .*(\n|\r\n|\r)*" }
+// { dg-output "Base: 0(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 Base::f .*(\n|\r\n|\r)*" }
+// { dg-output "Child0: 0(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 Child1::f .*(\n|\r\n|\r)*" }
+// { dg-output "Child1: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 Child2::f .*(\n|\r\n|\r)*" }
+// { dg-output "Child2: 20(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 Child3::f .*(\n|\r\n|\r)*" }
+// { dg-output "Child3: 30(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 7 Child4::f .*(\n|\r\n|\r)*" }
+// { dg-output "Child4: 40(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre5.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre5.C
new file mode 100644
index 00000000000..278a545055f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre5.C
@@ -0,0 +1,81 @@
+// basic test to ensure pre contracts work for free templates
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+template<typename T>
+int body(int a)
+  [[ pre: a > 0 ]]
+{
+  T t = a * 2.5;
+  return t;
+}
+
+template<typename T>
+int none(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<typename T>
+int arg0(T t)
+  [[ pre: t > 0 ]]
+{
+  return -t - 10;
+}
+
+template<typename T>
+int arg1(int a, T t)
+  [[ pre: a > 0 ]]
+  [[ pre: t > 0 ]]
+{
+  return -t * a;
+}
+
+template<typename T>
+T ret(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+int main(int, char**)
+{
+  printf("%d\n", body<int>(-1));
+  printf("%d\n", body<double>(-2));
+  printf("%d\n", none<int>(-1));
+  printf("%d\n", none<double>(-2));
+  printf("%d\n", arg0(-1));
+  printf("%d\n", arg0(-2.9));
+  printf("%d\n", arg1(-3, -1));
+  printf("%d\n", arg1(-4, -2.9));
+  printf("%d\n", (int)ret<int>(-3));
+  printf("%d\n", (int)ret<double>(-4.9));
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 8 body<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-2(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 8 body<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-5(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 16 none<int> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 16 none<double> .*(\n|\r\n|\r)*" }
+// { dg-output "2(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 23 arg0<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-9(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 23 arg0<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-7(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 30 arg1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 31 arg1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 30 arg1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 31 arg1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-11(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 ret<int> .*(\n|\r\n|\r)*" }
+// { dg-output "3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "4(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre6.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre6.C
new file mode 100644
index 00000000000..44e8e264b54
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre6.C
@@ -0,0 +1,74 @@
+// ensure no errors are thrown when we have to insert a decl for the internal
+// unchecked function after leaving a (possibly nested) namespace
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+namespace ns0
+{
+  int f(int a) [[ pre: a > 0 ]];
+}
+
+int ns0::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+namespace ns0
+{
+  namespace ns1
+  {
+    int f(int a) [[ pre: a > 0 ]];
+  }
+}
+
+int ns0::ns1::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+namespace ns0
+{
+  namespace ns1
+  {
+    int f2(int a) [[ pre: a > 0 ]];
+    namespace ns2
+    {
+      int f(int a) [[ pre: a > 0 ]];
+    }
+  }
+  int ns1::f2(int a) [[ pre: a > 0 ]]
+  {
+    return -a;
+  }
+}
+
+int ns0::ns1::ns2::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+namespace ns0
+{
+  struct S
+  {
+    int f(int a) [[ pre: a > 0 ]];
+  };
+  namespace ns1
+  {
+    struct S2
+    {
+      int f(int a) [[ pre: a > 0 ]];
+    };
+  }
+}
+
+int ns0::S::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+int ns0::ns1::S2::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre7.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre7.C
new file mode 100644
index 00000000000..aeb8fc042e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre7.C
@@ -0,0 +1,134 @@
+// ensure no errors are thrown when we have to insert a decl for the internal
+// unchecked function after leaving a (possibly nested) namespace
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+namespace ns0
+{
+  template<typename T>
+  int f(T a) [[ pre: a > 0 ]];
+}
+
+template<typename T>
+int ns0::f(T a) [[ pre: a > 0 ]]
+{
+  return (int)-a;
+}
+
+namespace ns0
+{
+  namespace ns1
+  {
+    template<typename T>
+    int f(T a) [[ pre: a > 0 ]];
+  }
+}
+
+template<typename T>
+int ns0::ns1::f(T a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+namespace ns0
+{
+  namespace ns1
+  {
+    template<typename T>
+    int f2(T a) [[ pre: a > 0 ]];
+    namespace ns2
+    {
+      template<typename T>
+      int f(T a) [[ pre: a > 0 ]];
+    }
+  }
+  template<typename T>
+  int ns1::f2(T a) [[ pre: a > 0 ]]
+  {
+    return -a;
+  }
+}
+
+template<typename T>
+int ns0::ns1::ns2::f(T a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+namespace ns0
+{
+  template<typename T>
+  struct S
+  {
+    int f(T a) [[ pre: a > 0 ]];
+  };
+  namespace ns1
+  {
+    template<typename T>
+    struct S2
+    {
+      int f(T a) [[ pre: a > 0 ]];
+    };
+  }
+}
+
+template<typename T>
+int ns0::S<T>::f(T a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<typename T>
+int ns0::ns1::S2<T>::f(T a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+#include <cstdio>
+int main(int, char**)
+{
+  printf ("%d\n", ns0::f(-1));
+  printf ("%d\n", ns0::ns1::f(-2));
+  printf ("%d\n", ns0::ns1::f2(-3));
+  printf ("%d\n", ns0::ns1::ns2::f(-4));
+  ns0::S<int> ns0_s;
+  printf ("%d\n", ns0_s.f(-5));
+  ns0::ns1::S2<int> ns0_ns1_s2;
+  printf ("%d\n", ns0_ns1_s2.f(-6));
+
+  printf ("%d\n", ns0::f(-7.5));
+  printf ("%d\n", ns0::ns1::f(-8.5));
+  printf ("%d\n", ns0::ns1::f2(-9.5));
+  printf ("%d\n", ns0::ns1::ns2::f(-10.5));
+  ns0::S<double> ns0_sd;
+  printf ("%d\n", ns0_sd.f(-11.5));
+  ns0::ns1::S2<double> ns0_ns1_s2d;
+  printf ("%d\n", ns0_ns1_s2d.f(-12.5));
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 13 ns0::f<int> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 ns0::ns1::f<int> .*(\n|\r\n|\r)*" }
+// { dg-output "2(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 46 ns0::ns1::f2<int> .*(\n|\r\n|\r)*" }
+// { dg-output "3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 53 ns0::ns1::ns2::f<int> .*(\n|\r\n|\r)*" }
+// { dg-output "4(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 76 ns0::S<int>::f .*(\n|\r\n|\r)*" }
+// { dg-output "5(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 82 ns0::ns1::S2<int>::f .*(\n|\r\n|\r)*" }
+// { dg-output "6(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 13 ns0::f<double> .*(\n|\r\n|\r)*" }
+// { dg-output "7(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 28 ns0::ns1::f<double> .*(\n|\r\n|\r)*" }
+// { dg-output "8(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 46 ns0::ns1::f2<double> .*(\n|\r\n|\r)*" }
+// { dg-output "9(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 53 ns0::ns1::ns2::f<double> .*(\n|\r\n|\r)*" }
+// { dg-output "10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 76 ns0::S<double>::f .*(\n|\r\n|\r)*" }
+// { dg-output "11(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 82 ns0::ns1::S2<double>::f .*(\n|\r\n|\r)*" }
+// { dg-output "12(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-pre9.C b/gcc/testsuite/g++.dg/cpp2a/contracts-pre9.C
new file mode 100644
index 00000000000..64c0cfa36df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-pre9.C
@@ -0,0 +1,146 @@
+// ensure no errors are thrown for various combinations of class templates
+// with guarded members
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+template<typename T>
+struct S
+{
+  int f(int a) [[ pre: a > 0 ]];
+  int g(int a) [[ pre: a > 0 ]];
+};
+
+template<typename T>
+int S<T>::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<typename T>
+int S<T>::g(int a) // Contract is inherited (error from line 10).
+{
+  return -a;
+}
+
+template<typename T>
+struct S_arg
+{
+  int f(T a) [[ pre: a > 0 ]];
+  int g(T a) [[ pre: a > 0 ]];
+};
+
+template<typename T>
+int S_arg<T>::f(T a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<typename T>
+int S_arg<T>::g(T a) // Contract is inherited (error from line 29).
+{
+  return -a;
+}
+
+template<typename T>
+struct S_ret
+{
+  T f(int a) [[ pre: a > 0 ]];
+  T g(int a) [[ pre: a > 0 ]];
+};
+
+template<typename T>
+T S_ret<T>::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<typename T>
+T S_ret<T>::g(int a) // Contract is inherited (error from line 48).
+{
+  return -a;
+}
+
+#include <cstdio>
+int main(int, char**)
+{
+  {
+    S<int> s_int;
+    printf ("s_int.f(-10): %d\n", s_int.f(-10));
+    printf ("s_int.g(-10): %d\n", s_int.g(-10));
+    printf ("s_int.f(10): %d\n", s_int.f(10));
+    printf ("s_int.g(10): %d\n", s_int.g(10));
+
+    S<double> s_double;
+    printf ("s_double.f(-10.5): %d\n", s_double.f(-10.5));
+    printf ("s_double.g(-10.5): %d\n", s_double.g(-10.5));
+    printf ("s_double.f(10.5): %d\n", s_double.f(10.5));
+    printf ("s_double.g(10.5): %d\n", s_double.g(10.5));
+  }
+
+  {
+    S_arg<int> s_arg_int;
+    printf ("s_arg_int.f(-10): %d\n", s_arg_int.f(-10));
+    printf ("s_arg_int.g(-10): %d\n", s_arg_int.g(-10));
+    printf ("s_arg_int.f(10): %d\n", s_arg_int.f(10));
+    printf ("s_arg_int.g(10): %d\n", s_arg_int.g(10));
+
+    S_arg<double> s_arg_double;
+    printf ("s_arg_double.f(-10): %d\n", s_arg_double.f(-10));
+    printf ("s_arg_double.g(-10): %d\n", s_arg_double.g(-10));
+    printf ("s_arg_double.f(10): %d\n", s_arg_double.f(10));
+    printf ("s_arg_double.g(10): %d\n", s_arg_double.g(10));
+  }
+
+  {
+    S_ret<int> s_ret_int;
+    printf ("s_ret_int.f(-10): %d\n", s_ret_int.f(-10));
+    printf ("s_ret_int.g(-10): %d\n", s_ret_int.g(-10));
+    printf ("s_ret_int.f(10): %d\n", s_ret_int.f(10));
+    printf ("s_ret_int.g(10): %d\n", s_ret_int.g(10));
+
+    S_ret<double> s_ret_double;
+    printf ("s_ret_double.f(-10): %f\n", s_ret_double.f(-10));
+    printf ("s_ret_double.g(-10): %f\n", s_ret_double.g(-10));
+    printf ("s_ret_double.f(10): %f\n", s_ret_double.f(10));
+    printf ("s_ret_double.g(10): %f\n", s_ret_double.g(10));
+  }
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 14 S<int>::f .*(\n|\r\n|\r)*" }
+// { dg-output "s_int.f.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 S<int>::g .*(\n|\r\n|\r)*" }
+// { dg-output "s_int.g.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "s_int.f.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "s_int.g.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 14 S<double>::f .*(\n|\r\n|\r)*" }
+// { dg-output "s_double.f.-10.5.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 S<double>::g .*(\n|\r\n|\r)*" }
+// { dg-output "s_double.g.-10.5.: 10(\n|\r\n|\r)*" }
+// { dg-output "s_double.f.10.5.: -10(\n|\r\n|\r)*" }
+// { dg-output "s_double.g.10.5.: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 33 S_arg<int>::f .*(\n|\r\n|\r)*" }
+// { dg-output "s_arg_int.f.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 29 S_arg<int>::g .*(\n|\r\n|\r)*" }
+// { dg-output "s_arg_int.g.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "s_arg_int.f.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "s_arg_int.g.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 33 S_arg<double>::f .*(\n|\r\n|\r)*" }
+// { dg-output "s_arg_double.f.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 29 S_arg<double>::g .*(\n|\r\n|\r)*" }
+// { dg-output "s_arg_double.g.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "s_arg_double.f.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "s_arg_double.g.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 52 S_ret<int>::f .*(\n|\r\n|\r)*" }
+// { dg-output "s_ret_int.f.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 48 S_ret<int>::g .*(\n|\r\n|\r)*" }
+// { dg-output "s_ret_int.g.-10.: 10(\n|\r\n|\r)*" }
+// { dg-output "s_ret_int.f.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "s_ret_int.g.10.: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 52 S_ret<double>::f .*(\n|\r\n|\r)*" }
+// { dg-output "s_ret_double.f.-10.: 10.000000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 48 S_ret<double>::g .*(\n|\r\n|\r)*" }
+// { dg-output "s_ret_double.g.-10.: 10.000000(\n|\r\n|\r)*" }
+// { dg-output "s_ret_double.f.10.: -10.000000(\n|\r\n|\r)*" }
+// { dg-output "s_ret_double.g.10.: -10.000000(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl1.C
new file mode 100644
index 00000000000..58d0aafeff5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl1.C
@@ -0,0 +1,149 @@
+// generic error tests for contract redecls with generalized redecl
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+// OK if equivalent -- even through renames.
+int g0(int a) [[ pre: a > 0 ]];
+int g0(int a) [[ pre: a > 0 ]];
+
+int g0b(int a) [[ pre: a > 0 ]];
+int g0b(int b) [[ pre: b > 0 ]];
+int g0b(int c) [[ pre: c > 0 ]]
+{
+  return 0;
+}
+
+// OK if specified before.
+int g1(int a) [[ pre: a > 0 ]];
+int g1(int a);
+
+// OK if specified after.
+int g2(int a);
+int g2(int a) [[ pre: a > 0 ]];
+
+int g2b(int a);
+int g2b(int b) [[ pre: b > 0 ]];
+
+// can add to non-virtual methods
+struct G0
+{
+  int f(int a);
+};
+
+// OK to add contracts at the point of definition.
+int G0::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+struct G1
+{
+  int f1(int a);
+};
+
+// OK to redeclare functions and add constraints...
+int G1::f1(int a) [[ pre: a > 0 ]];
+
+// ...and leave them off later.
+int G1::f1(int a)
+{
+  return -a;
+}
+
+int f0(int a) [[ pre: a > 0 ]];
+int f0(int a) [[ pre: a > 0 ]] [[ pre: a > 10 ]]; // { dg-error "different number of contracts" }
+
+int f1(int a) [[ pre: a > 0 ]] [[ pre: a > 10 ]];
+int f1(int a) [[ pre: a > 0 ]]; // { dg-error "different number of contracts" }
+
+int f2(int a) [[ pre: a > 0 ]];
+int f2(int a) [[ pre: a < 0 ]]; // { dg-error "mismatched contract" }
+
+int f3(int a) { return a; }
+int f3(int a) [[ pre: a < 0 ]]; // { dg-error "cannot add contracts" }
+
+struct Base
+{
+  virtual int f(int a) [[ pre: a > 0 ]];
+};
+
+struct Child : Base
+{
+  int f(int a) [[ pre: a < 0 ]]; // { dg-error "mismatched contract" }
+};
+
+struct S1
+{
+  virtual int f(int a); // contracts are inherited at the point of declarations
+};
+
+int S1::f(int a) [[ pre: a > 0 ]] // { dg-error "cannot add" }
+{
+  return -a;
+}
+
+struct S2
+{
+  int f() { return 0; }
+};
+
+int S2::f(); // OK?
+
+
+struct S3
+{
+  int f() { return 0; }
+};
+
+int S3::f() [[pre: true]]; // { dg-error "cannot add contracts" }
+
+
+// The initial decl of a guarded member must appear inside the class.
+struct S4
+{
+  int f(int a);
+};
+
+int S4::g(int a) [[ pre: a > 0 ]]; // { dg-error "no declaration matches" }
+
+
+struct S5
+{
+  template<typename T>
+  S5(T a);
+};
+
+template<typename T>
+S5::S5(T a) [[ pre: a > 0 ]]
+{
+}
+
+struct S6
+{
+  template<typename T>
+  S6(T a);
+};
+
+template<typename T>
+S6::S6(T a) [[ pre: a > 0 ]];
+
+template<typename T>
+S6::S6(T a)
+{
+}
+
+int p0(int n)
+  [[ post r: r > 0 && r == n ]]
+  [[ post r: r > 1 && r == n ]]
+  [[ post r: r > 2 && r == n ]]
+  [[ post r: r > 3 && r == n ]];
+
+int p0(int z)
+  [[ post r: r > 0 && r == z ]]
+  [[ post r1: r1 > 1 && r1 == z ]]
+  [[ post r2: r2 > 2 && r2 == z ]]
+  [[ post r3: r3 > 3 && r3 == z ]]
+{
+  return z;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl2.C
new file mode 100644
index 00000000000..a9ac7fc60de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl2.C
@@ -0,0 +1,150 @@
+// generic error tests for generalized contract redecls
+// FIXME: merge into contracts-redecl1
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+// allowed to repeat contracts or omit them
+int g0(int a) [[ pre: a > 0 ]];
+int g0(int a) [[ pre: a > 0 ]];
+
+int g1(int a) [[ pre: a > 0 ]];
+int g1(int a);
+
+// allowed to add from none if generalized redecl is on (by default)
+int g2(int a);
+int g2(int a) [[ pre: a > 0 ]];
+
+// can add to non-virtual methods
+struct G0
+{
+  int f(int a);
+};
+
+int G0::f(int a) [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+struct G1
+{
+  int f(int a);
+};
+
+int G1::f(int a) [[ pre: a > 0 ]];
+
+int G1::f(int a)
+{
+  return -a;
+}
+
+// allowed to redeclare even without contracts
+struct G2
+{
+  int f(int a);
+};
+
+int G2::f(int a);
+
+
+int f0(int a) [[ pre: a > 0 ]];
+int f0(int a) [[ pre: a > 0 ]] [[ pre: a > 10 ]]; // { dg-error "different number of contracts" }
+
+int f1(int a) [[ pre: a > 0 ]];
+int f1(int a) [[ pre: a < 0 ]]; // { dg-error "mismatched contract" }
+
+int f2(int a) { return a; }
+int f2(int a) [[ pre: a < 0 ]]; // { dg-error "cannot add contracts after definition" }
+
+struct Base
+{
+  virtual int f(int a) [[ pre: a > 0 ]];
+};
+
+struct Child : Base
+{
+  int f(int a) [[ pre: a < 0 ]]; // { dg-error "mismatched contract" }
+};
+
+// the initial decl of a guarded member must appear inside the class
+struct F2
+{
+  int f(int a);
+};
+
+int F2::g(int a) [[ pre: a > 0 ]]; // { dg-error "no declaration matches" }
+// FIXME if we move F2 down then a different error makes F2 undeclared
+
+struct F0
+{
+  virtual int f(int a);
+};
+
+int F0::f(int a); // { dg-error "declaration.*is not definition" }
+
+struct F1
+{
+  virtual int f(int a);
+};
+
+int F1::f(int a) [[ pre: a > 0 ]] // { dg-error "cannot add" }
+{
+  return -a;
+}
+
+// cannot "re"declare members of a forward declared class
+struct F2;
+int F2::test(); // { dg-error "no declaration matches" }
+int F2::test2() [[ pre: true ]]; // { dg-error "no declaration matches" }
+
+// can only redeclare member functions
+struct F3
+{
+  int x;
+  typedef int my_int;
+
+  struct Inner0;
+  struct Inner1;
+  enum my_enum0; // { dg-error "use of enum.*without previous decl" }
+  enum my_enum1 { E1, E2 };
+
+  int test0();
+  int test1();
+  int test2();
+};
+
+int F3::x{-1}; // { dg-error "is not a static data member" }
+typedef double F3::my_int; // { dg-error "typedef name may not be a nested-name-specifier" }
+struct F3::Inner0; // { dg-warning "declaration.*does not declare anything" }
+
+struct F3::Inner1 { };
+
+enum F3::my_enum1 { E0, E1, END }; // { dg-error "multiple definition" }
+
+struct F4
+{
+  int test0();
+
+  int F3::test0() [[ pre: true ]]; // { dg-error "cannot declare member function" }
+  friend int F3::test1();
+  friend int F3::test2();
+};
+int F3::test2() [[ pre: true ]] { return -1; }
+
+void dummy0()
+{
+  int F4::test0() [[ pre: true ]]; // { dg-error "qualified-id in declaration" }
+}
+
+namespace ns0
+{
+  typedef int value;
+  struct X
+  {
+    int test1(value);
+    typedef double value;
+    int test2(value);
+  };
+  int X::test1(value); // { dg-error "no declaration matches" }
+  int X::test2(value);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl3.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl3.C
new file mode 100644
index 00000000000..fdfca3a65ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl3.C
@@ -0,0 +1,195 @@
+// basic test to ensure contracts generalized redecl works
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+namespace defining
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  struct T1
+  {
+    void vfun(int m, double n);
+    int fun(int m, double n);
+    double fun2(int m, double n);
+    S funend(int m, double n);
+  };
+
+  void T1::vfun(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+  int T1::fun(int m, double n)
+    [[ pre: x < 0 ]]
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double T1::fun2(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]]
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+}
+
+namespace nondefining
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  struct T1
+  {
+    void vfun(int m, double n);
+    int fun(int m, double n);
+    double fun2(int m, double n);
+    S funend(int m, double n);
+  };
+
+  void T1::vfun(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]];
+  int T1::fun(int m, double n)
+    [[ pre: x < 0 ]];
+  double T1::fun2(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]];
+
+  void T1::vfun(int m, double n)
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+  int T1::fun(int m, double n)
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double T1::fun2(int m, double n)
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+}
+
+int main(int, char**) {
+  // defining redecl
+  {
+    int x = 11;
+    double y = 11.5;
+
+    defining::T1 t1;
+    t1.vfun(x, y);
+
+    int f = 13;
+    f = t1.fun(x, y);
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = t1.fun2(x, y);
+    printf("main::d: %f\n", d);
+    defining::S s = t1.funend(x, y);
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+
+  // nondefining redecl
+  {
+    int x = 12;
+    double y = 12.5;
+
+    nondefining::T1 t1;
+    t1.vfun(x, y);
+
+    int f = 13;
+    f = t1.fun(x, y);
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = t1.fun2(x, y);
+    printf("main::d: %f\n", d);
+    nondefining::S s = t1.funend(x, y);
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+  return 0;
+}
+
+namespace defining
+{
+  S T1::funend(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("funend::x: %d\n", x);
+    S s;
+    s.z = true;
+    return s;
+  }
+}
+
+namespace nondefining
+{
+  S T1::funend(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]];
+
+  S T1::funend(int m, double n)
+  {
+    printf("funend::x: %d\n", x);
+    S s;
+    s.z = true;
+    return s;
+  }
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 25 defining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 26 defining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 32 defining::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 40 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 41 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 42 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 138 defining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 139 defining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 nondefining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 69 nondefining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 71 nondefining::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 73 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 74 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 75 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 76 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 151 nondefining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 152 nondefining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl4.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl4.C
new file mode 100644
index 00000000000..c1e234226b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl4.C
@@ -0,0 +1,56 @@
+// test that free functions can be redeclared with contracts without affecting
+// normal default parm handling
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+int f(int a, int, int c = 10);
+int f(int a, int b = 11, int);
+int f(int a, int b, int c)
+  [[ pre: a < 0 ]]
+  [[ pre: b < 0 ]]
+  [[ pre: c < 0 ]];
+
+int f(int, int, int);
+
+int f(int a, int b, int c)
+{
+  printf("f: a: %d, b: %d, c: %d\n", a, b, c);
+  return a * b - c;
+}
+
+int f(int a = 12, int, int);
+
+int main(int, char **)
+{
+  f(1,1,1);
+  printf("=====\n");
+  f(1,1);
+  printf("=====\n");
+  f(1);
+  printf("=====\n");
+  f();
+  printf("=====\n");
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 10 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 f .*(\n|\r\n|\r)*" }
+// { dg-output "f: a: 1, b: 1, c: 1(\n|\r\n|\r)*" }
+// { dg-output "=====(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 f .*(\n|\r\n|\r)*" }
+// { dg-output "f: a: 1, b: 1, c: 10(\n|\r\n|\r)*" }
+// { dg-output "=====(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 f .*(\n|\r\n|\r)*" }
+// { dg-output "f: a: 1, b: 11, c: 10(\n|\r\n|\r)*" }
+// { dg-output "=====(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 f .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 f .*(\n|\r\n|\r)*" }
+// { dg-output "f: a: 12, b: 11, c: 10(\n|\r\n|\r)*" }
+// { dg-output "=====(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl5.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl5.C
new file mode 100644
index 00000000000..ea4835f1899
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl5.C
@@ -0,0 +1,101 @@
+// generic error tests for generalized contract redecls
+//   we also test for the warning diagnostic for strict redecl
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts -fcontract-strict-declarations=on" }
+
+// allowed to repeat contracts or omit them
+int g0(int a) [[ pre: a > 0 ]];
+int g0(int a) [[ pre: a > 0 ]];
+
+int g1(int a) [[ pre: a > 0 ]];
+int g1(int a);
+
+// allowed to add from none if generalized redecl is on (by default)
+int g2(int a);
+int g2(int a) [[ pre: a > 0 ]]; // { dg-warning "adds contracts" }
+int g2(int a) [[ pre: a > 0 ]]; // { dg-bogus "adds contracts" }
+
+// can add to non-virtual methods
+struct G0
+{
+  int f(int a);
+};
+
+int G0::f(int a) [[ pre: a > 0 ]] // { dg-warning "adds contracts" }
+{
+  return -a;
+}
+
+struct G1
+{
+  int f(int a);
+};
+
+int G1::f(int a) [[ pre: a > 0 ]]; // { dg-warning "adds contracts" }
+// { dg-warning "outside of class is not definition" "" { target *-*-* } .-1 }
+
+int G1::f(int a);
+// { dg-warning "outside of class is not definition" "" { target *-*-* } .-1 }
+
+int G1::f(int a) [[ pre: a > 0 ]];
+// { dg-warning "outside of class is not definition" "" { target *-*-* } .-1 }
+
+int G1::f(int a)
+{
+  return -a;
+}
+
+// allowed to redeclare even without contracts
+struct G2
+{
+  int f(int a);
+};
+
+int G2::f(int a); // { dg-warning "outside of class is not definition" }
+
+
+int f0(int a) [[ pre: a > 0 ]];
+int f0(int a) [[ pre: a > 0 ]] [[ pre: a > 10 ]]; // { dg-error "different number of contracts" }
+
+int f1(int a) [[ pre: a > 0 ]];
+int f1(int a) [[ pre: a < 0 ]]; // { dg-error "mismatched contract" }
+
+int f2(int a) { return a; }
+int f2(int a) [[ pre: a < 0 ]]; // { dg-error "cannot add contracts after definition" }
+
+struct Base
+{
+  virtual int f(int a) [[ pre: a > 0 ]];
+};
+
+struct Child : Base
+{
+  int f(int a) [[ pre: a < 0 ]]; // { dg-error "mismatched contract" }
+};
+
+// the initial decl of a guarded member must appear inside the class
+struct F2
+{
+  int f(int a);
+};
+
+int F2::g(int a) [[ pre: a > 0 ]]; // { dg-error "no declaration matches" }
+// FIXME if we move F2 down then a different error makes F2 undeclared
+
+struct F0
+{
+  virtual int f(int a);
+};
+
+int F0::f(int a); // { dg-error "declaration.*is not definition" }
+
+struct F1
+{
+  virtual int f(int a);
+};
+
+int F1::f(int a) [[ pre: a > 0 ]] // { dg-error "cannot add" }
+{
+  return -a;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl6.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl6.C
new file mode 100644
index 00000000000..e79a5aa38ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl6.C
@@ -0,0 +1,195 @@
+// basic test to ensure contracts generalized redecl works
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+namespace defining
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  struct T1
+  {
+    void vfun(int m, double n) const;
+    int fun(int m, double n) volatile;
+    double fun2(int m, double n) const volatile;
+    static S funend(int m, double n);
+  };
+
+  void T1::vfun(int m, double n) const
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+  int T1::fun(int m, double n) volatile
+    [[ pre: x < 0 ]]
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double T1::fun2(int m, double n) const volatile
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]]
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+}
+
+namespace nondefining
+{
+  int x = 10;
+  double y = 10.5;
+
+  struct S
+  {
+    bool z;
+  };
+
+  struct T1
+  {
+    void vfun(int m, double n) const;
+    int fun(int m, double n) volatile;
+    double fun2(int m, double n) const volatile;
+    static S funend(int m, double n);
+  };
+
+  void T1::vfun(int m, double n) const
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]];
+  int T1::fun(int m, double n) volatile
+    [[ pre: x < 0 ]];
+  double T1::fun2(int m, double n) const volatile
+    [[ pre: x < 0 ]]
+    [[ pre: y < 0 ]]
+    [[ pre: m < 0 ]]
+    [[ pre: n < 0 ]];
+
+  void T1::vfun(int m, double n) const
+  {
+    printf("vfun::x: %d\n", x);
+  }
+
+  int T1::fun(int m, double n) volatile
+  {
+    printf("fun::x: %d\n", x);
+    return x;
+  }
+
+  double T1::fun2(int m, double n) const volatile
+  {
+    printf("fun2::x: %d fun2::y: %f\n", x, y);
+    return y;
+  }
+}
+
+int main(int, char**) {
+  // defining redecl
+  {
+    int x = 11;
+    double y = 11.5;
+
+    defining::T1 t1;
+    t1.vfun(x, y);
+
+    int f = 13;
+    f = t1.fun(x, y);
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = t1.fun2(x, y);
+    printf("main::d: %f\n", d);
+    defining::S s = defining::T1::funend(x, y);
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+
+  // nondefining redecl
+  {
+    int x = 12;
+    double y = 12.5;
+
+    nondefining::T1 t1;
+    t1.vfun(x, y);
+
+    int f = 13;
+    f = t1.fun(x, y);
+    printf("main::f: %d\n", f);
+    double d = 13.37;
+    d = t1.fun2(x, y);
+    printf("main::d: %f\n", d);
+    nondefining::S s = nondefining::T1::funend(x, y);
+    printf("main::s.z: %d\n", s.z ? 1 : 0);
+  }
+  return 0;
+}
+
+namespace defining
+{
+  S T1::funend(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]]
+  {
+    printf("funend::x: %d\n", x);
+    S s;
+    s.z = true;
+    return s;
+  }
+}
+
+namespace nondefining
+{
+  S T1::funend(int m, double n)
+    [[ pre: x < 0 ]]
+    [[ pre: m < 0 ]];
+
+  S T1::funend(int m, double n)
+  {
+    printf("funend::x: %d\n", x);
+    S s;
+    s.z = true;
+    return s;
+  }
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 25 defining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 26 defining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 32 defining::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 40 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 41 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 42 defining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 138 defining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 139 defining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 nondefining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 69 nondefining::T1::vfun .*(\n|\r\n|\r)*" }
+// { dg-output "vfun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 71 nondefining::T1::fun .*(\n|\r\n|\r)*" }
+// { dg-output "fun::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::f: 10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 73 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 74 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 75 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 76 nondefining::T1::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "fun2::x: 10 fun2::y: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "main::d: 10.500000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 151 nondefining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 152 nondefining::T1::funend .*(\n|\r\n|\r)*" }
+// { dg-output "funend::x: 10(\n|\r\n|\r)*" }
+// { dg-output "main::s.z: 1(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl7.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl7.C
new file mode 100644
index 00000000000..050c8ee3191
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl7.C
@@ -0,0 +1,64 @@
+// test that contracts can be added during (defining) friend declarations
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+struct T;
+
+struct S
+{
+  int now(int a, T *t) [[ pre: a > 0 ]] [[ pre: x < 0 ]];
+
+
+  int x{-1};
+};
+
+int now(int a, T *t) [[ pre: a > 0 ]];
+int later(int a, T *t);
+int both(int a, T *t) [[ pre: a > 0 ]];
+
+struct T
+{
+  friend int now(int a, T *t);
+  friend int both(int a, T *t) [[ pre: a > 0 ]]
+  {
+    printf("both: a: %d, t->pri: %d\n", a, t->pri);
+    return -a * t->pri;
+  }
+
+  friend int S::now(int a, T *t);
+
+  int x{1};
+  private:
+    int pri{-10};
+};
+
+int S::now(int a, T *t)
+{
+  printf("S::now: a: %d, t->pri: %d\n", a, t->pri);
+  return -a * t->pri;
+}
+
+int now(int a, T *t)
+{
+  printf("now: a: %d, t->pri: %d\n", a, t->pri);
+  return -a * t->pri;
+}
+
+int main(int, char**)
+{
+  T t;
+  S s;
+  s.now(-10, &t);
+
+  now(-20, &t);
+  both(-22, &t);
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 9 S::now .*(\n|\r\n|\r)*" }
+// { dg-output "S::now: a: -10, t->pri: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 15 now .*(\n|\r\n|\r)*" }
+// { dg-output "now: a: -20, t->pri: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 22 both .*(\n|\r\n|\r)*" }
+// { dg-output "both: a: -22, t->pri: -10(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-redecl8.C b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl8.C
new file mode 100644
index 00000000000..ffa41dee5e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-redecl8.C
@@ -0,0 +1,65 @@
+// test that contracts are matched on friend decls when the type is complete
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+struct T;
+
+int both(int x, T *t) [[ pre: x > 0 ]] { return 0; }
+int both2(int x, T *t) [[ pre: x > 0 ]];
+
+template<typename Z>
+int fn(int x, Z *z) [[ pre: x > 0 ]];
+
+template<typename Z>
+int fn2(int x, Z *z);
+
+template<typename Z>
+int fn3(int x, Z *z) [[ pre: x > 0 ]];
+
+template<>
+int fn3<T>(int x, T *z) [[ pre: x > 1 ]];
+
+struct T
+{
+  friend int both2(int x, T *t) [[ pre: x > 1 ]] // { dg-error "mismatched" }
+  {
+    return 0;
+  }
+
+  // friends are not members and thus not in the complete class context.
+  friend int hidden(int x, T *t)
+  [[ pre: x > 1 ]] [[ pre: t->pri > 0 ]] // { dg-error "has no member" }
+  {
+    return x;
+  }
+
+  /* cannot define friend spec, so we never get to matching contracts
+  friend int fn<T>(int x, T *t)
+    [[ pre: t->pri > 0 ]] { return 0; } // error defining explicit spec friend
+    */
+
+  // bad, general contracts must match general
+  template<typename Z>
+  friend int fn(int x, Z *z)
+    [[ pre: z->pri > 1 ]] { return 0; } // { dg-error "mismatched" }
+
+  // fine, can add contracts
+  template<typename Z>
+  friend int fn2(int x, Z *z)
+    [[ pre: z->pri > 1 ]] { return 0; } // { dg-bogus "mismatched" }
+
+  /* cannot declare without definition, so dup friend can't occur:
+  friend int dup(int x, T *t)
+    [[ pre: t->pri > 0 ]]; // error non-defining friend with contracts
+  friend int dup(int x, T *t)
+    [[ pre: t->pri > 1 ]]; // error non-defining friend with contracts
+    */
+
+  int x{1};
+  private:
+    int pri{-10};
+};
+
+int hidden(int x, T *t)
+  [[ pre: x > 0 ]] [[ pre: t->pri > 1 ]]; // { dg-error "mismatched" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-attr1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-attr1.C
new file mode 100644
index 00000000000..c9e7b9cec8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-attr1.C
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+template<typename T>
+[[z]]
+[[nodiscard]]
+T fun(T n)
+  [[ pre: n > 0 ]]
+  [[ post r: r > 0 ]] // { dg-warning ".z. attribute.*ignored" }
+{
+  return n;
+}
+
+int main(int, char**) {
+  fun(-5); // { dg-warning "ignoring return value" }
+  fun(-5.3); // { dg-warning "ignoring return value" }
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec1.C b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec1.C
new file mode 100644
index 00000000000..57ba7653543
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec1.C
@@ -0,0 +1,121 @@
+// basic test to ensure pre contracts work for free template specializations
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+template<typename T>
+int body(int a)
+  [[ pre: a > 0 ]]
+{
+  T t = a * 2.5;
+  return t;
+}
+
+template<>
+int body<double>(int a)
+  [[ pre: a > 0 ]]
+{
+  double t = a * 3.3;
+  return t;
+}
+
+template<typename T>
+int none(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<>
+int none<double>(int a)
+  [[ pre: a > 0 ]]
+{
+  return a - 100;
+}
+
+template<typename T>
+int arg0(T t)
+  [[ pre: t > 0 ]]
+{
+  return -t - 10;
+}
+
+template<>
+int arg0<double>(double t)
+  [[ pre: t > 0 ]]
+{
+  return -t + 10;
+}
+
+template<typename T>
+int arg1(int a, T t)
+  [[ pre: a > 0 ]]
+  [[ pre: t > 0 ]]
+{
+  return -t * a;
+}
+
+template<>
+int arg1<double>(int a, double t)
+  [[ pre: a > 0 ]]
+  [[ pre: t > 0 ]]
+{
+  return -t * a + 17;
+}
+
+template<typename T>
+T ret(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<>
+double ret<double>(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a * 3.3;
+}
+
+
+int main(int, char**)
+{
+  printf("%d\n", body<int>(-1));
+  printf("%d\n", body<double>(-1));
+  printf("%d\n", none<int>(-1));
+  printf("%d\n", none<double>(-1));
+  printf("%d\n", arg0(-1));
+  printf("%d\n", arg0(-1.0));
+  printf("%d\n", arg1(-3, -1));
+  printf("%d\n", arg1(-3, -1.0));
+  printf("%d\n", (int)ret<int>(-1));
+  printf("%d\n", (int)ret<double>(-1));
+  printf("%f\n", ret<double>(-1));
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 8 body<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-2(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 16 body<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 24 none<int> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 31 none<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-101(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 38 arg0<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-9(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 45 arg0<double> .*(\n|\r\n|\r)*" }
+// { dg-output "11(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 52 arg1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 53 arg1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 60 arg1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 61 arg1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "14(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 68 ret<int> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 75 ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 75 ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "3.300000(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec2.C b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec2.C
new file mode 100644
index 00000000000..25982dfc826
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec2.C
@@ -0,0 +1,395 @@
+// basic test to ensure contracts work for class and member specializations
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+// template specializations can have differing contracts
+template<typename T>
+int body(int a)
+  [[ pre: a > 0 ]]
+{
+  T t = a * 2.5;
+  return t;
+}
+
+template<>
+int body<double>(int a)
+  [[ pre: a > 1 ]]
+{
+  double t = a * 3.3;
+  return t;
+}
+
+template<typename T>
+int none(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<>
+int none<double>(int a)
+  [[ pre: a > 1 ]]
+{
+  return a - 100;
+}
+
+template<typename T>
+int arg0(T t)
+  [[ pre: t > 0 ]]
+{
+  return -t - 10;
+}
+
+template<>
+int arg0<double>(double t)
+  [[ pre: t > 1 ]]
+{
+  return -t + 10;
+}
+
+template<typename T>
+int arg1(int a, T t)
+  [[ pre: a > 0 ]]
+  [[ pre: t > 0 ]]
+{
+  return -t * a;
+}
+
+template<>
+int arg1<double>(int a, double t)
+  [[ pre: a > 1 ]]
+  [[ pre: t > 1 ]]
+{
+  return -t * a + 17;
+}
+
+template<typename T>
+T ret(int a)
+  [[ pre: a > 0 ]]
+{
+  return -a;
+}
+
+template<>
+double ret<double>(int a)
+  [[ pre: a > 1 ]]
+{
+  return -a * 3.3;
+}
+
+// template specializations can have no contracts
+template<typename T>
+int g1(T t) [[ pre: t > 0 ]]
+{
+  return (int)t;
+}
+
+template<>
+int g1<double>(double t)
+{
+  return (int)t;
+}
+
+// template specializations can have no contracts in the first decl but add
+// them later
+template<typename T>
+int g2(T t) [[ pre: t > 0 ]]
+{
+  return (int)t;
+}
+
+template<>
+int g2<double>(double t);
+
+template<>
+int g2<double>(double t)
+  [[ pre: t < 0 ]]
+{
+  return (int)t;
+}
+
+template<>
+int g2<char>(char t)
+  [[ pre: t < 'c' ]]
+{
+  return (int)t;
+}
+
+// contracts can be different on the general template, partial and full specs
+template<typename T, typename S>
+struct G3
+{
+  void f(T t, S s)
+    [[ pre: t > 0 ]]
+    [[ pre: s > 0 ]]
+  {
+    printf ("G3 general T S\n");
+  }
+};
+
+template<typename S>
+struct G3<int, S>
+{
+  void f(int t, S s);
+};
+
+template<typename S>
+void G3<int, S>::f(int t, S s)
+  [[ pre: t > 1 ]]
+  [[ pre: s > 1 ]]
+{
+  printf ("G3 partial int S\n");
+}
+
+template<>
+void G3<int, double>::f(int t, double s)
+  [[ pre: t > 2 ]]
+  [[ pre: s > 2 ]]
+{
+  printf ("G3 full int double\n");
+}
+
+struct C
+{
+  bool operator>(int rhs) { return false; }
+};
+
+// deletes contracts
+template<>
+void G3<int, C>::f(int t, C s);
+
+template<>
+void G3<int, C>::f(int t, C s)
+{
+  printf ("G3 full int C\n");
+};
+
+// specialized ctors
+template<typename T, typename S>
+struct G4
+{
+  G4(T t, S s)
+    [[ pre: t > 0 ]]
+    [[ pre: s > 0 ]]
+    [[ post: x > 0 ]]
+  {
+    printf ("G4 general T S\n");
+    return;
+  }
+  int x{-1};
+};
+
+template<typename S>
+struct G4<char, S>
+{
+  G4(char t, S s)
+    [[ pre: t > 'c' ]]
+    [[ pre: s > 3 ]]
+    [[ post: x2 > 3 ]]
+  {
+    printf ("G4 partial char S\n");
+    return;
+  }
+  int x2{-1};
+};
+
+template<>
+G4<double, double>::G4(double, double)
+{
+  printf ("G4 full double double\n");
+  return;
+}
+
+template<>
+G4<double, char>::G4(double a, char b)
+  [[ pre: a > 0 ]]
+  [[ pre: b > 'b' ]]
+  [[ post: x > 1 ]]
+{
+  printf ("G4 full double char\n");
+  return;
+}
+
+// crossover of template classes and template members ok
+template<typename T, typename S>
+struct G5
+{
+  template<typename P>
+  void f(T t, S s, P r)
+    [[ pre: t > 0 ]]
+    [[ pre: s > 0 ]]
+    [[ pre: r > 0 ]]
+  {
+    printf ("G5 gen T S, f gen R\n");
+  }
+};
+
+template<typename S>
+struct G5<char, S>
+{
+  template<typename R>
+  void f(char x, S y, R z)
+    [[ pre: x > 'z' ]]
+    [[ pre: y > 1 ]]
+    [[ pre: z > 1 ]]
+  {
+    printf ("G5 partial char S, f gen R\n");
+  }
+};
+
+template<>
+template<typename Q>
+void G5<double, double>::f(double a, double b, Q c)
+  [[ pre: a > 2 ]]
+  [[ pre: b > 2 ]]
+  [[ pre: c > 2 ]]
+{
+  printf ("G5 full double double, f gen R\n");
+}
+
+int main(int, char**)
+{
+  printf("%d\n", body<int>(-1));
+  printf("%d\n", body<double>(-1));
+  printf("%d\n", none<int>(-1));
+  printf("%d\n", none<double>(-1));
+  printf("%d\n", arg0(-1));
+  printf("%d\n", arg0(-1.0));
+  printf("%d\n", arg1(-3, -1));
+  printf("%d\n", arg1(-3, -1.0));
+  printf("%d\n", (int)ret<int>(-1));
+  printf("%d\n", (int)ret<double>(-1));
+  printf("%f\n", ret<double>(-1));
+
+  printf("%d\n", g1(-1));
+  printf("%d\n", g1(-1.0));
+
+  printf("%d\n", g2(-1));
+  printf("%d\n", g2(1.0));
+  printf("%d\n", g2('d'));
+
+  G3<double, double> g3_gen;
+  G3<int, int> g3_partial;
+  G3<int, double> g3_full;
+  g3_gen.f(-1.0, -1.0); // general
+  g3_partial.f(-2, -2); // partial spec
+  g3_full.f(-3, -3.0); // full spec
+
+  G3<char, char> g3_gen2;
+  G3<int, char> g3_partial2;
+  g3_gen2.f((char)-1, (char)-1);
+  g3_partial2.f(-1, (char)-1);
+
+  G3<int, C> g3_full2;
+  g3_full2.f(5, C{});
+  g3_full2.f(-5, C{});
+
+  G4 g4_gen{-1, -1};
+  G4 g4_full1{-1.0, -1.0};
+  G4 g4_full2{-1.0, (char)'b'};
+  G4 g4_partial{(char)'c', -5};
+
+  G5<int, int> g5_gen;
+  g5_gen.f(-1, -1, -2);
+  g5_gen.f(-1, -1, -2.0);
+
+  G5<char, int> g5_part;
+  g5_part.f('a', -1, -2);
+  g5_part.f('a', -1, -2.1);
+
+  G5<double, double> g5_full;
+  g5_full.f(-1.0, -1.0, -2);
+  g5_full.f(-1.0, -1.0, -2.1);
+  return 0;
+}
+
+
+// { dg-output "default std::handle_contract_violation called: .*.C 9 body<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-2(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 17 body<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 25 none<int> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 32 none<double> .*(\n|\r\n|\r)*" }
+// { dg-output "-101(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 39 arg0<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-9(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 46 arg0<double> .*(\n|\r\n|\r)*" }
+// { dg-output "11(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 53 arg1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 54 arg1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 61 arg1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 62 arg1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "14(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 69 ret<int> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 76 ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 76 ret<double> .*(\n|\r\n|\r)*" }
+// { dg-output "3.300000(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 83 g1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-1(\n|\r\n|\r)*" }
+// { dg-output "-1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 97 g2<int> .*(\n|\r\n|\r)*" }
+// { dg-output "-1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 107 g2<double> .*(\n|\r\n|\r)*" }
+// { dg-output "1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 114 g2<char> .*(\n|\r\n|\r)*" }
+// { dg-output "100(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 124 G3<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 125 G3<double, .*(\n|\r\n|\r)*" }
+// { dg-output "G3 general T S(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 139 G3<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 140 G3<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G3 partial int S(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 147 G3<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 148 G3<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G3 full int double(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 124 G3<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 125 G3<char, .*(\n|\r\n|\r)*" }
+// { dg-output "G3 general T S(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 139 G3<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 140 G3<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G3 partial int S(\n|\r\n|\r)*" }
+// { dg-output "G3 full int C(\n|\r\n|\r)*" }
+// { dg-output "G3 full int C(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 173 G4<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 174 G4<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G4 general T S(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 175 G4<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G4 full double double(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 206 G4<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 207 G4<double, .*(\n|\r\n|\r)*" }
+// { dg-output "G4 full double char(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 208 G4<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 187 G4<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 188 G4<char, .*(\n|\r\n|\r)*" }
+// { dg-output "G4 partial char S(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 189 G4<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 220 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 221 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 222 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 gen T S, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 220 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 221 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 222 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 gen T S, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 233 G5<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 234 G5<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 235 G5<char, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 partial char S, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 233 G5<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 234 G5<char, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 235 G5<char, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 partial char S, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 244 G5<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 245 G5<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 246 G5<double, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 full double double, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 244 G5<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 245 G5<double, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 246 G5<double, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 full double double, f gen R(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec3.C b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec3.C
new file mode 100644
index 00000000000..879172f1513
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts-tmpl-spec3.C
@@ -0,0 +1,45 @@
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+template<typename T, typename S>
+struct G5
+{
+  template<typename R>
+  void f(T t, S s, R r)
+    [[ pre: t > 0 ]] [[ pre: s > 0 ]] [[ pre: r > 0 ]]
+  {
+    printf ("G5 gen T S, f gen R\n");
+  }
+};
+
+// specializations can remove contracts
+template<>
+template<typename R>
+void G5<double, double>::f(double a, double b, R c)
+{
+  printf ("G5 full double double, f gen R\n");
+}
+
+int main(int, char**) {
+  G5<double, double> g5_full;
+  g5_full.f(-1.0, -1.0, -2);
+  g5_full.f(-1.0, -1.0, -2.1);
+
+  G5<int, double> g5_gen;
+  g5_gen.f(-1, -1.0, -2);
+  g5_gen.f(-1, -1.0, -2.1);
+  return 0;
+}
+
+// { dg-output "G5 full double double, f gen R(\n|\r\n|\r)*" }
+// { dg-output "G5 full double double, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 gen T S, f gen R(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 G5<int, .*(\n|\r\n|\r)*" }
+// { dg-output "G5 gen T S, f gen R(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts1.C b/gcc/testsuite/g++.dg/cpp2a/contracts1.C
new file mode 100644
index 00000000000..6655e016221
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts1.C
@@ -0,0 +1,49 @@
+// generic assert contract parsing checks
+//   check omitted, 'default', 'audit', and 'axiom' contract levels parse
+//   check that all concrete semantics parse
+//   check omitted, '%default' contract roles parse
+//   ensure that an invalid contract level 'invalid' errors
+//   ensure that a predicate referencing an undefined variable errors
+//   ensure that a missing colon after contract level errors
+//   ensure that an invalid contract role 'invalid' errors
+//   ensure that a missing colon after contract role errors
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+static_assert (__cpp_contracts >= 201906);
+static_assert (__cpp_contracts_literal_semantics >= 201906);
+static_assert (__cpp_contracts_roles >= 201906);
+
+int main()
+{
+  int x;
+
+  [[assert: x >= 0]];
+  [[assert default: x < 0]];
+  [[assert audit: x == 0]];
+  [[assert axiom: x == 1]];
+
+  [[assert: x > 0 ? true : false]];
+  [[assert: x < 0 ? true : false]];
+
+  [[assert: x = 0]]; // { dg-error "expected .]. before .=. token" }
+
+  [[assert ignore: x >= 0]];
+  [[assert assume: x >= 0]];
+  [[assert check_never_continue: x >= 0]];
+  [[assert check_maybe_continue: x >= 0]];
+
+  [[assert %default: x >= 0]];
+  [[assert default %default: x < 0]];
+  [[assert audit %default: x == 0]];
+  [[assert axiom %default: x == 1]];
+
+  [[assert check_always_continue: x >= 0]]; // { dg-error "expected contract level" }
+  [[assert invalid: x == 0]]; // { dg-error "expected contract level" }
+  [[assert: y == 0]]; // { dg-error ".y. was not declared in this scope" }
+  [[assert default x == 0]]; // { dg-error "expected .:. before .x." }
+  [[assert %default x >= 0]]; // { dg-error "expected .:. before .x." }
+
+  [[assert %invalid: x >= 0]]; // TODO: optional warning?
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts10.C b/gcc/testsuite/g++.dg/cpp2a/contracts10.C
new file mode 100644
index 00000000000..ce0723c3db4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts10.C
@@ -0,0 +1,73 @@
+// general checks to ensure that contract violations are generated during
+// runtime when appropriate
+// each check also validates the expected file name, line number, function,
+// predicate, and contract level are included in the violation_info object
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-build-level=audit -fcontract-continuation-mode=on" }
+
+namespace tns
+{
+  int fun()
+  {
+    int x = 1;
+    [[ assert: x < 0 ]];
+    return 0;
+  }
+  int fun2();
+
+  struct TestType
+  {
+    static int fun();
+    static int fun2()
+    {
+      int x = 1;
+      [[ assert: x < 0 ]];
+      return 0;
+    }
+  };
+}
+
+int tns::fun2()
+{
+  int x = 1;
+  [[ assert: x < 0 ]];
+  return 0;
+}
+
+int tns::TestType::fun()
+{
+  int x = 1;
+  [[ assert: x < 0 ]];
+  return 0;
+}
+
+int main()
+{
+  int x = 100;
+  [[assert: x < 0]];
+  [[assert default: x < 1]];
+  [[assert audit: x < 2]];
+// contract_violation.line_number() may eventually come from
+// std::source_location which *is* affected by the #line macro; our current
+// implementation conforms to this so we've included it as a check
+#line 100
+  [[assert: x < 3]];
+  [[assert axiom: x < 4]];
+
+  tns::fun();
+  tns::fun2();
+
+  tns::TestType::fun();
+  tns::TestType::fun2();
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 47 main .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 48 main .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 49 main .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 100 main .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 13 tns::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 33 tns::fun2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 40 tns::TestType::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 24 tns::TestType::fun2 .*(\n|\r\n|\r)*" }
+ 
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts11.C b/gcc/testsuite/g++.dg/cpp2a/contracts11.C
new file mode 100644
index 00000000000..b41bc535e5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts11.C
@@ -0,0 +1,103 @@
+// ensure that assert contract predicates that are not convertible to bool
+// generate an error
+// ensure the same for instatiated template functions
+// ensure the same for non-instatiated template functions when the predicate
+// is not dependent on the template parameters
+// ensure template parameter dependent, potentially non-boolean, contract
+// predicates do not generate an error if never instatiated
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+void fun()
+{
+  return;
+}
+
+template<typename T>
+void fun2(T a)
+{
+  [[assert: fun()]]; // { dg-error "could not convert|in argument" }
+}
+
+template<typename T>
+void fun3(T a)
+{
+  [[assert: fun()]]; // { dg-error "could not convert|in argument" }
+}
+
+template<typename T>
+void fun4(T a)
+{
+  [[assert: a.fun()]];
+}
+
+struct test
+{
+  void fun() { }
+  void fun2() { }
+};
+
+template<typename T>
+void fun5(T a)
+{
+  [[assert: a.fun2()]]; // { dg-error "could not convert" }
+}
+
+struct VoidFun
+{
+  void fun() { }
+};
+struct BoolFun
+{
+  bool fun() { return true; }
+};
+
+template<typename T>
+void fun6(T a)
+{
+  [[ assert: a.fun() ]]; // { dg-error "could not convert" }
+}
+
+template void fun6(VoidFun);
+
+template<typename T>
+void fun7(T a)
+{
+  [[ assert: a.fun() ]];
+}
+
+template void fun7(BoolFun);
+
+struct ImplicitBool
+{
+  operator bool() { return true; }
+};
+struct ExplicitBool
+{
+  explicit operator bool() { return true; }
+};
+
+template<typename T>
+void fun8(T a)
+{
+  [[ assert: T() ]];
+}
+
+template void fun8(ImplicitBool);
+template void fun8(ExplicitBool);
+
+void fun9()
+{
+  [[ assert: ImplicitBool() ]];
+  [[ assert: ExplicitBool() ]];
+}
+
+int main()
+{
+  [[assert: fun()]]; // { dg-error "could not convert" }
+  fun2(1);
+
+  test t;
+  fun5(t);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts12.C b/gcc/testsuite/g++.dg/cpp2a/contracts12.C
new file mode 100644
index 00000000000..f888d51296d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts12.C
@@ -0,0 +1,15 @@
+// ensure that constants for contract levels are inserted into the binary when
+// used and omitted when the runtime check is not generated
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts -fcontract-build-level=default" }
+// { dg-final { scan-assembler-not "audit" } }
+// { dg-final { scan-assembler "default" } }
+
+int main()
+{
+  int x = 1;
+  [[assert: x < 0]];
+  [[assert default: x < 0]];
+  [[assert audit: x < 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts13.C b/gcc/testsuite/g++.dg/cpp2a/contracts13.C
new file mode 100644
index 00000000000..14ba0e96006
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts13.C
@@ -0,0 +1,51 @@
+// ensure that passing asserts do not affect constexpr functions
+// ensure that failing asserts generate an error in a constexpr function
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+constexpr int wfun(int a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+constexpr int ffun(int a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+template<typename T>
+constexpr int tfun(T a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+template<typename T>
+constexpr int wtfun(T a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+template<typename T>
+constexpr int ftfun(T a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+constexpr int explicitfn(int a) {
+  [[assert ignore: a > 0]];
+  [[assert check_never_continue: a > 0]];
+  return a;
+}
+
+int main(int, char **) {
+  constexpr int a = wfun(10);
+  constexpr int b = ffun(-10); // { dg-message "in .constexpr. expansion" }
+  // { dg-error "contract predicate" "" { target *-*-* } 12 }
+  constexpr int c = wtfun(10);
+  constexpr int d = ftfun(-10);  // { dg-message "in .constexpr. expansion" }
+  // { dg-error "contract predicate" "" { target *-*-* } 30 }
+  constexpr int e = explicitfn(-10); // { dg-message "in .constexpr. expansion" }
+  // { dg-error "contract predicate" "" { target *-*-* } 36 }
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts14.C b/gcc/testsuite/g++.dg/cpp2a/contracts14.C
new file mode 100644
index 00000000000..cef8a322315
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts14.C
@@ -0,0 +1,81 @@
+// ensure that exceptions thrown inside a custom contract violation handler
+// are catchable up the call stack
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <iostream>
+#include <contract>
+
+int
+__on_contract_violation (bool continue_,
+        int line_number,
+        const char * file_name,
+        const char * function_name,
+        const char * comment,
+        const char * assertion_level,
+        const char * assertion_role,
+        int continuation_mode);
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom std::handle_contract_violation called:"
+    << " " << violation.line_number()
+    << " " << violation.file_name()
+    << std::endl;
+  throw -violation.line_number();
+}
+
+int fun() {
+  int x = 0;
+  [[ assert: x < 0 ]];
+  return 0;
+}
+
+int fun2() {
+  __on_contract_violation(true, 1, "T1", "T2", "T3", "T4", "T5", 1);
+  return 1;
+}
+
+int fun3() {
+  fun();
+  return 2;
+}
+
+int main(int, char**) {
+  try {
+    int x = 0;
+    [[ assert: x < 0 ]];
+  } catch(int &ex) {
+    std::cerr << "synth caught direct: " << ex << std::endl;
+  }
+
+  try {
+    fun2();
+  } catch(int &ex) {
+    std::cerr << "caught lib direct: " << ex << std::endl;
+  }
+
+  try {
+    fun();
+  } catch(int &ex) {
+    std::cerr << "synth caught indirect: " << ex << std::endl;
+  }
+
+  try {
+    fun3();
+  } catch(int &ex) {
+    std::cerr << "synth caught double indirect: " << ex << std::endl;
+  }
+
+  std::cerr << "end main" << std::endl;
+  return 0;
+}
+
+// { dg-output "custom std::handle_contract_violation called: 45 .*/contracts14.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught direct: -45(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 1 T1(\n|\r\n|\r)*" }
+// { dg-output "caught lib direct: -1(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 28 .*/contracts14.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught indirect: -28(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 28 .*/contracts14.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught double indirect: -28(\n|\r\n|\r)*" }
+// { dg-output "end main" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts15.C b/gcc/testsuite/g++.dg/cpp2a/contracts15.C
new file mode 100644
index 00000000000..bdab22b99fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts15.C
@@ -0,0 +1,79 @@
+// ensure that exceptions thrown inside a custom contract violation handler
+// are not catchable up the call stack when failing in a noexcept function
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <iostream>
+#include <contract>
+
+int
+__on_contract_violation (bool continue_,
+        int line_number,
+        const char * file_name,
+        const char * function_name,
+        const char * comment,
+        const char * assertion_level,
+        const char * assertion_role,
+        int continuation_mode);
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom std::handle_contract_violation called:"
+    << " " << violation.line_number()
+    << " " << violation.file_name()
+    << std::endl;
+  throw -violation.line_number();
+}
+
+int fun() noexcept {
+  int x = 0;
+  [[ assert: x < 0 ]];
+  return 0;
+}
+
+int fun2() {
+  __on_contract_violation(true, 1, "T1", "T2", "T3", "T4", "T5", 1);
+  return 1;
+}
+
+int fun3() {
+  fun();
+  return 2;
+}
+
+int main(int, char**) {
+  try {
+    int x = 0;
+    [[ assert: x < 0 ]];
+  } catch(int &ex) {
+    std::cerr << "synth caught direct: " << ex << std::endl;
+  }
+
+  try {
+    fun2();
+  } catch(int &ex) {
+    std::cerr << "caught lib direct: " << ex << std::endl;
+  }
+
+  try {
+    fun();
+  } catch(int &ex) {
+    std::cerr << "synth caught indirect: " << ex << std::endl;
+  }
+
+  try {
+    fun3();
+  } catch(int &ex) {
+    std::cerr << "synth caught double indirect: " << ex << std::endl;
+  }
+
+  std::cerr << "end main" << std::endl;
+  return 0;
+}
+
+// { dg-output "custom std::handle_contract_violation called: 45 .*/contracts15.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught direct: -45(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 1 T1(\n|\r\n|\r)*" }
+// { dg-output "caught lib direct: -1(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 28 .*/contracts15.C(\n|\r\n|\r)*" }
+// { dg-output "terminate called after throwing an instance of .int.(\n|\r\n|\r)*" }
+// { dg-shouldfail "throwing in noexcept" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts16.C b/gcc/testsuite/g++.dg/cpp2a/contracts16.C
new file mode 100644
index 00000000000..67d9390b694
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts16.C
@@ -0,0 +1,34 @@
+// ensure that exceptions thrown inside a custom contract violation handler
+// are not catchable up the call stack even when continue mode is off
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+#include <iostream>
+#include <contract>
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom std::handle_contract_violation called:"
+    << " " << violation.line_number()
+    << " " << violation.file_name()
+    << std::endl;
+  throw -violation.line_number();
+}
+
+int fun() {
+  int x = 0;
+  [[ assert: x < 0 ]];
+  return 0;
+}
+
+int main(int, char**) {
+  try {
+    fun();
+  } catch(int &ex) {
+    std::cerr << "synth caught indirect: " << ex << std::endl;
+  }
+
+  return 0;
+}
+
+// { dg-output "custom std::handle_contract_violation called: 18 .*/contracts16.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught indirect: -18(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts17.C b/gcc/testsuite/g++.dg/cpp2a/contracts17.C
new file mode 100644
index 00000000000..dbe03af05f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts17.C
@@ -0,0 +1,35 @@
+// ensure that exceptions thrown inside a custom contract violation handler
+// are not catchable up the call stack when continue mode is off and the
+// assert fails in a noexcept function
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+#include <iostream>
+#include <contract>
+
+void handle_contract_violation(const std::contract_violation &violation) {
+  std::cerr << "custom std::handle_contract_violation called:"
+    << " " << violation.line_number()
+    << " " << violation.file_name()
+    << std::endl;
+  throw -violation.line_number();
+}
+
+int fun() noexcept {
+  int x = 0;
+  [[ assert: x < 0 ]];
+  return 0;
+}
+
+int main(int, char**) {
+  try {
+    fun();
+  } catch(int &ex) {
+    std::cerr << "synth caught indirect: " << ex << std::endl;
+  }
+
+  return 0;
+}
+
+// { dg-output "custom std::handle_contract_violation called: 19 .*/contracts17.C(\n|\r\n|\r)*" }
+// { dg-shouldfail "throwing in noexcept" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts18.C b/gcc/testsuite/g++.dg/cpp2a/contracts18.C
new file mode 100644
index 00000000000..e8163ba4ab2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts18.C
@@ -0,0 +1,15 @@
+// check that a valid program using assertions compiles and runs
+//   ensure an axiom with a failing predicate doesn't prevent a successful run
+//   (axiom level contracts are never checked at runtime)
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-role=custom:never,ignore,ignore" }
+
+int main()
+{
+  int x = 1;
+  [[assert axiom: x < 0]];
+  [[assert %custom: x > 0]];
+  [[assert audit %custom: x < 0]];
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts19.C b/gcc/testsuite/g++.dg/cpp2a/contracts19.C
new file mode 100644
index 00000000000..4a8b43a3186
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts19.C
@@ -0,0 +1,19 @@
+// check that a valid program using assertions compiles and runs
+//   ensure an axiom with a failing predicate doesn't prevent a successful run
+//   (axiom level contracts are never checked at runtime)
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-role=custom:maybe,maybe,ignore" }
+
+int main()
+{
+  int x = 10;
+  [[assert axiom: x < 0]];
+  [[assert %custom: x < 0]];
+  [[assert audit %custom: x < 1]];
+  [[assert axiom %custom: x < 1]];
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 11 main .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 main .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts2.C b/gcc/testsuite/g++.dg/cpp2a/contracts2.C
new file mode 100644
index 00000000000..9535e077d36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts2.C
@@ -0,0 +1,13 @@
+// check that a valid program using assertions compiles and runs
+//   ensure an axiom with a failing predicate doesn't prevent a successful run
+//   (axiom level contracts are never checked at runtime)
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+
+int main()
+{
+  int x = 1;
+  [[assert axiom: x < 0]];
+  [[assert default: x > 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts20.C b/gcc/testsuite/g++.dg/cpp2a/contracts20.C
new file mode 100644
index 00000000000..adce5d70d40
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts20.C
@@ -0,0 +1,11 @@
+// test that contract attributes cause errors pre-c++2a
+// { dg-do compile { target c++17_only } }
+
+int fun(int a)
+  [[ pre: a > 0 ]] // { dg-error "contracts are only available with .-fcontracts." }
+  [[ post r: r < 0 ]] // { dg-error "contracts are only available with .-fcontracts." }
+{
+  [[ assert: a != 0 ]]; // { dg-error "contracts are only available with .-fcontracts." }
+  return -a;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts22.C b/gcc/testsuite/g++.dg/cpp2a/contracts22.C
new file mode 100644
index 00000000000..91e32b9d9b2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts22.C
@@ -0,0 +1,32 @@
+// ensure a default level assert with a failing predicate does not generate an
+// error during runtime when the contracts mode is off
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-mode=off" }
+// { dg-output "returning from main" }
+#include <cstdio>
+
+int constexpr f()
+{
+  constexpr int x = 1;
+  [[assert default: x < 0]];
+  return x;
+}
+
+template<typename T> int k()
+{
+  int x = 1;
+  [[assert default: x < 0]];
+  return x;
+}
+
+
+int main()
+{
+  int x = 1;
+  [[assert default: x < 0]];
+  constexpr int x2 = f();
+  int x3 = k<int>();
+
+  printf ("returning from main\n");
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts24.C b/gcc/testsuite/g++.dg/cpp2a/contracts24.C
new file mode 100644
index 00000000000..70a54f95a93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts24.C
@@ -0,0 +1,15 @@
+// check that a valid program using assertions compiles and runs
+//   ensure an axiom with a failing predicate doesn't prevent a successful run
+//   (axiom level contracts are never checked at runtime)
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-semantic=default:never -fcontract-semantic=audit:ignore -fcontract-semantic=axiom:ignore" }
+
+int main()
+{
+  int x = 1;
+  [[assert axiom: x < 0]];
+  [[assert: x > 0]];
+  [[assert audit: x < 0]];
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts25.C b/gcc/testsuite/g++.dg/cpp2a/contracts25.C
new file mode 100644
index 00000000000..01217807bc1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts25.C
@@ -0,0 +1,57 @@
+// ensure that passing asserts do not affect constexpr functions
+// ensure that failing asserts generate an error at runtime in constexpr funcs
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+constexpr int wfun(int a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+constexpr int ffun(int a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+template<typename T>
+constexpr int tfun(T a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+template<typename T>
+constexpr int wtfun(T a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+template<typename T>
+constexpr int ftfun(T a) {
+  [[assert: a > 0]];
+  return a;
+}
+
+constexpr int explicitfn(int a) {
+  [[assert ignore: a > 0]];
+  [[assert check_maybe_continue: a > 0]];
+  return a;
+}
+
+int main(int, char **) {
+  int a = wfun(10);
+  int b = ffun(-10);
+  int c = wtfun(10);
+  int d = ftfun(-10);
+
+  int e = explicitfn(-10);
+
+  int z = ftfun(-10.0);
+
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 12 ffun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 30 ftfun<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 36 explicitfn .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 30 ftfun<double> .*(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts3.C b/gcc/testsuite/g++.dg/cpp2a/contracts3.C
new file mode 100644
index 00000000000..ecb9fdb1e65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts3.C
@@ -0,0 +1,13 @@
+// ensure a default level assert with a failing predicate generates an error
+// during runtime when the contract build level is default
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+// { dg-shouldfail "assert violation" }
+// { dg-output "default std::handle_contract_violation called" }
+
+int main()
+{
+  int x = 1;
+  [[assert default: x < 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts35.C b/gcc/testsuite/g++.dg/cpp2a/contracts35.C
new file mode 100644
index 00000000000..ddd80025afc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts35.C
@@ -0,0 +1,47 @@
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+#include <cstdio>
+
+struct S
+{
+  template<typename T>
+  S(T a) [[ pre: a > 0 ]] [[ pre: a > 10 ]];
+};
+
+template<typename T>
+S::S(T a)
+{
+  printf ("S::S(T): %d\n", (int)a);
+}
+
+struct S1
+{
+  template<typename T>
+  S1(T a) [[ pre: a > 0 ]] [[ pre: a > 10 ]]
+  {
+    printf ("S1::S1(T): %d\n", (int)a);
+  }
+};
+
+int main(int, char **) {
+  S s{-1};
+  S s2{-2.5};
+
+  S1 s1_1{-3};
+  S1 s1_2{-4.5};
+  return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 8 S::S<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 8 S::S<int> .*(\n|\r\n|\r)*" }
+// { dg-output "S::S.T.: -1(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 8 S::S<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 8 S::S<double> .*(\n|\r\n|\r)*" }
+// { dg-output "S::S.T.: -2(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 20 S1::S1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 20 S1::S1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "S1::S1.T.: -3(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 20 S1::S1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 20 S1::S1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "S1::S1.T.: -4(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts4.C b/gcc/testsuite/g++.dg/cpp2a/contracts4.C
new file mode 100644
index 00000000000..a43fb9f98e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts4.C
@@ -0,0 +1,11 @@
+// ensure an audit level assert with a failing predicate does not generate an
+// error during runtime when the contract build level is default
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts" }
+
+int main()
+{
+  int x = 1;
+  [[assert audit: x < 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts5.C b/gcc/testsuite/g++.dg/cpp2a/contracts5.C
new file mode 100644
index 00000000000..0fa0ec83be5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts5.C
@@ -0,0 +1,13 @@
+// ensure an audit level assert with a failing predicate generates an error
+// during runtime when the contract build level is audit
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-build-level=audit" }
+// { dg-shouldfail "assert violation" }
+// { dg-output "default std::handle_contract_violation called" }
+
+int main()
+{
+  int x = 1;
+  [[assert audit: x < 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts6.C b/gcc/testsuite/g++.dg/cpp2a/contracts6.C
new file mode 100644
index 00000000000..59c010e5d39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts6.C
@@ -0,0 +1,11 @@
+// ensure a default level assert with a failing predicate does not generate an
+// error during runtime when the contract build level is off
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-build-level=off" }
+
+int main()
+{
+  int x = 1;
+  [[assert default: x < 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts7.C b/gcc/testsuite/g++.dg/cpp2a/contracts7.C
new file mode 100644
index 00000000000..eaad8f0fc9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts7.C
@@ -0,0 +1,14 @@
+// ensure a default level assert with a failing predicate does generates an
+// error during runtime but lets the program continue and complete
+// successfully when the contract build level is default but continuation on
+// contract failure is switched on
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+// { dg-output "default std::handle_contract_violation called" }
+
+int main()
+{
+  int x = 1;
+  [[assert default: x < 0]];
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts8.C b/gcc/testsuite/g++.dg/cpp2a/contracts8.C
new file mode 100644
index 00000000000..9c8a6b5d8c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts8.C
@@ -0,0 +1,43 @@
+// generic assert contract parsing checks
+//   ensure that existing generalized attribute parsing is not intefered with
+//   ensure that an assert contract cannot chain into an empty attribute list
+//   ensure that an attribute list cannot chain into an assert contract
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts" }
+
+constexpr bool fun(int x) {
+  return x < 0;
+}
+
+namespace tns {
+  constexpr bool f(int x) {
+    return x < 0;
+  }
+}
+
+bool assert(int x) {
+  return x < 0;
+}
+
+int main()
+{
+  constexpr int x = 1;
+  [[fun(x)]]; // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[fun(x), assert(x)]]; // { dg-warning "attributes at the beginning of statement are ignored" }
+
+  [[assert default: fun(x), ]]; // { dg-error "expected ']'" }
+  [[assert default: fun(x) ]];
+
+  [[fun(x), assert default: fun(x)]]; // { dg-error "expected .]. before .default." }
+  // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 }
+  [[fun(x), assert: fun(x)]]; // { dg-error "expected .]. before .:. token" }
+  // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 }
+  [[fun(x), assert fun(x)]]; // { dg-error "expected .]. before .fun." }
+  // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 }
+  [[ using tns: f(x) ]]; // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[ using tns: f(x), assert default: fun(x) ]]; // { dg-error "expected .]. before .default." }
+  // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 }
+  [[ using tns: f(x), , default: fun(x) ]]; // { dg-error "expected .]. before .:." }
+  // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/contracts9.C b/gcc/testsuite/g++.dg/cpp2a/contracts9.C
new file mode 100644
index 00000000000..f566628ec44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/contracts9.C
@@ -0,0 +1,45 @@
+// ensure that dependent and non-dependent asserts inside templated
+// functions parse without error whether the function is instatiated or not
+// ensure that assert contract checks are generated inside called templates
+// ensure that template functions can be used as assert predicates
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
+
+template<typename T>
+int fun1(int a, T b)
+{
+  [[ assert: a > 0 ]];
+  [[ assert: (long long)b > 0 ]];
+  return a > 0;
+}
+
+template<typename T>
+struct test
+{
+  static int fun(int a, T b) {
+    [[ assert: a > 0 ]];
+    [[ assert: b > 0 ]];
+    return a > 0;
+  }
+};
+
+int main()
+{
+  fun1(1, -1);
+  fun1(-1, 1.0);
+  fun1(-1, "test");
+
+  [[ assert: fun1(-1, -5) ]];
+  [[ assert: test<int>::fun(10, -6) ]];
+  [[ assert: test<double>::fun(10.0, -7) ]];
+  // return 0;
+}
+
+// { dg-output "default std::handle_contract_violation called: .*.C 12 fun1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 fun1<double> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 fun1<const char.> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 11 fun1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 12 fun1<int> .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 32 main .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 21 test<int>::fun .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 21 test<double>::fun .*(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/modules/contracts-1_a.C b/gcc/testsuite/g++.dg/modules/contracts-1_a.C
new file mode 100644
index 00000000000..c1c2f6add93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-1_a.C
@@ -0,0 +1,46 @@
+// Basic test to ensure that guarded templates correctly serialize and
+// deserialize their contracts through the CMI.
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-continuation-mode=on" }
+module;
+#include <cstdio>
+#include <contract>
+export module foo;
+// { dg-module-cmi foo }
+
+export int violation_count{0};
+export void handle_contract_violation(const std::contract_violation &violation)
+{
+  violation_count++;
+  printf("violation_count: %d\n", violation_count);
+}
+
+export int nontemplate(int n)
+  [[ pre: n > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return -n;
+}
+
+export
+template<typename T>
+T fn(T n)
+  [[ pre: n > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+  return n;
+}
+
+export
+template<typename T>
+void void_fn(T n)
+  [[ pre: n < 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+}
+
+export void foo_fn()
+{
+  fn(5);
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-1_b.C b/gcc/testsuite/g++.dg/modules/contracts-1_b.C
new file mode 100644
index 00000000000..30c15f6928b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-1_b.C
@@ -0,0 +1,33 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-continuation-mode=on" }
+module;
+#include <cstdio>
+export module bar;
+// { dg-module-cmi bar }
+import foo;
+
+template<typename T>
+bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; }
+
+export
+template<typename T>
+T bar_fn(T n)
+  [[ pre: bar_fn_pre(n) && n > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+  return n;
+}
+
+int main(int, char**)
+{
+  nontemplate(5);
+  nontemplate(-5);
+  fn(5);
+  fn(-5);
+  void_fn(5);
+  void_fn(-5);
+  bar_fn(5);
+  bar_fn(-5);
+  return violation_count == 6 ? 0 : -1;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-2_a.C b/gcc/testsuite/g++.dg/modules/contracts-2_a.C
new file mode 100644
index 00000000000..cb9efd7ec07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-2_a.C
@@ -0,0 +1,49 @@
+// Basic test to ensure that guarded function contracts are correctly
+// serialized and deserialized through the CMI.
+// This also tries to ensure that entities referenced in a function's
+// contracts are correctly marked as a dependency of the function itself and
+// serialized in the correct order.
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:maybe,maybe,ignore" }
+module;
+#include <cstdio>
+#include <contract>
+export module foo;
+// { dg-module-cmi foo }
+
+export int violation_count{0};
+export int violation_line_sum{0};
+export void handle_contract_violation(const std::contract_violation &violation)
+{
+  violation_count++;
+  violation_line_sum += violation.line_number () * violation_count;
+  printf("violation: %d %d\n", violation_count, violation_line_sum);
+}
+
+export int fn2(int n);
+export int fn_in2(int n);
+export int pre_print(int n) { printf("pre_print(%d)\n", n); return n; }
+
+export int fn_in1(int n) [[ pre: pre_print(n) > 0 ]]
+{
+  printf("%s blah (%d)\n", __FUNCTION__, n);
+  return n;
+}
+export int fn_in2(int x) [[ pre: pre_print(x) > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, x);
+  return x;
+}
+
+export int fn_iso(int n);
+
+export int fn1(int n)
+  [[ pre: pre_print(n) > 0 ]];
+
+export int fn2(int n)
+  [[ pre: pre_print(n) > 0 ]];
+
+export int pre_print2(int n);
+
+export int fn3(int n)
+  [[ pre: pre_print2(n) > 0 ]];
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-2_b.C b/gcc/testsuite/g++.dg/modules/contracts-2_b.C
new file mode 100644
index 00000000000..01939aeb947
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-2_b.C
@@ -0,0 +1,35 @@
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:maybe,maybe,ignore" }
+module;
+#include <cstdio>
+module foo;
+
+int fn1(int x)
+{
+  printf("%s(%d)\n", __FUNCTION__, x);
+  return x;
+}
+
+int fn_iso(int n) [[ pre: pre_print(n) > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+  return n;
+}
+
+int pre_print2(int n)
+{
+  printf("pre_print(%d)\n", n);
+  return n;
+}
+
+int fn2(int x)
+{
+  printf("%s(%d)\n", __FUNCTION__, x);
+  return x;
+}
+
+int fn3(int x)
+{
+  printf("%s(%d)\n", __FUNCTION__, x);
+  return x;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-2_c.C b/gcc/testsuite/g++.dg/modules/contracts-2_c.C
new file mode 100644
index 00000000000..58938e0e6de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-2_c.C
@@ -0,0 +1,22 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:maybe,maybe,ignore" }
+import foo;
+
+int main(int, char**)
+{
+  int x = -1;
+
+  fn_iso(x--);
+  fn1(x--);
+  fn2(x--);
+  fn3(x--);
+  fn_in1(x--);
+  fn_in2(x--);
+  return (violation_count == 6 && violation_line_sum == 729) ? 0 : -1;
+}
+
+// TODO does any of this actually get verified?
+// { dg-output "pre_print.-1.(\n|\r\n|\r)*" }
+// { dg-output "violation: 1 12(\n|\r\n|\r)*" }
+// { dg-output "fn_iso.-1.(\n|\r\n|\r)*" }
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-3_a.C b/gcc/testsuite/g++.dg/modules/contracts-3_a.C
new file mode 100644
index 00000000000..ab362a37851
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-3_a.C
@@ -0,0 +1,41 @@
+// Basic test to ensure that guarded templates correctly serialize and
+// deserialize their contracts through the CMI.
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-continuation-mode=on" }
+module;
+#include <cstdio>
+#include <contract>
+export module foo;
+// { dg-module-cmi foo }
+
+export int violation_count{0};
+export void handle_contract_violation(const std::contract_violation &violation)
+{
+  violation_count++;
+  printf("violation_count: %d\n", violation_count);
+}
+
+export int nontemplate(int n)
+  [[ pre: n > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  return -n;
+}
+
+export
+template<typename T>
+T fn(T n)
+  [[ pre: n > 0 ]]
+  [[ post r: r > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+  return n;
+}
+
+export
+template<typename T>
+void void_fn(T n)
+  [[ pre: n < 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-3_b.C b/gcc/testsuite/g++.dg/modules/contracts-3_b.C
new file mode 100644
index 00000000000..b1d6375391b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-3_b.C
@@ -0,0 +1,35 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:ignore,ignore,ignore" }
+module;
+#include <cstdio>
+export module bar;
+// { dg-module-cmi bar }
+import foo;
+
+template<typename T>
+bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; }
+
+export
+template<typename T>
+T bar_fn(T n)
+  [[ pre: bar_fn_pre(n) && n > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, n);
+  return n;
+}
+
+int main(int, char**)
+{
+  nontemplate(5);
+  nontemplate(-5);
+  fn(5);
+  fn(-5);
+  fn(5.3);
+  fn(-5.3);
+  void_fn(5);
+  void_fn(-5);
+  bar_fn(5);
+  bar_fn(-5);
+  return violation_count == 7 ? 0 : -1;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-4_a.C b/gcc/testsuite/g++.dg/modules/contracts-4_a.C
new file mode 100644
index 00000000000..ab6c8112f26
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-4_a.C
@@ -0,0 +1,28 @@
+// Test that template contracts are not reintpreted when the reinterpret
+// contracts flag is not set, regardless of the current TU's contract
+// configuration.
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:maybe,maybe,ignore" }
+module;
+#include <cstdio>
+#include <contract>
+export module foo;
+// { dg-module-cmi foo }
+
+export int violation_count{0};
+export void handle_contract_violation(const std::contract_violation &violation)
+{
+  violation_count++;
+  printf("violation_count: %d\n", violation_count);
+}
+
+export template<typename T>
+T fn_t(T t)
+  [[ pre: t > 0 ]]
+  [[ pre audit %custom: t > 0 ]]
+{
+  printf("%s(%d)\n", __FUNCTION__, t);
+  return t;
+}
+
+export int fn_int(int n);
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-4_b.C b/gcc/testsuite/g++.dg/modules/contracts-4_b.C
new file mode 100644
index 00000000000..65b9287b211
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-4_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:ignore,ignore,ignore" }
+module foo;
+
+int fn_int(int n)
+{
+  return fn_t(n);
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-4_c.C b/gcc/testsuite/g++.dg/modules/contracts-4_c.C
new file mode 100644
index 00000000000..84fcb616314
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-4_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:ignore,ignore,ignore" }
+export module bar;
+import foo;
+
+export int bar_fn_int(int n)
+{
+  return fn_t(n);
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-4_d.C b/gcc/testsuite/g++.dg/modules/contracts-4_d.C
new file mode 100644
index 00000000000..dc56251d1d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-4_d.C
@@ -0,0 +1,22 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fcontracts" }
+module;
+#include <cstdio>
+export module baz;
+import foo;
+import bar;
+
+int main(int, char**)
+{
+  int x = -1;
+
+  printf("calling fn_int\n");
+  fn_int(x--);
+  printf("calling bar_fn_int\n");
+  bar_fn_int(x--);
+
+  return violation_count - 4;
+}
+
+// TODO verify dg-output as well once the testsuite supports it
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-tpl-friend-1_a.C b/gcc/testsuite/g++.dg/modules/contracts-tpl-friend-1_a.C
new file mode 100644
index 00000000000..5e6d848aaa4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-tpl-friend-1_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts -fcontracts" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+void foo (int, void *);
+void foo (float, void *);
+
+template <typename T> class TPL
+{
+  friend void foo (T, void *); // { dg-warning "non-template function" }
+
+  T member;
+};
+
+template class TPL<float>;  // instantiate
+
diff --git a/gcc/testsuite/g++.dg/modules/contracts-tpl-friend-1_b.C b/gcc/testsuite/g++.dg/modules/contracts-tpl-friend-1_b.C
new file mode 100644
index 00000000000..f872c9248d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/contracts-tpl-friend-1_b.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts -fcontracts" }
+
+module foo;
+
+void foo (int x, void *p)
+  [[ pre: x > 0 ]]
+{
+  auto *obj = reinterpret_cast<TPL<int> *> (p);
+
+  obj->member = x;
+}
+
+void foo (float x, void *p)
+  [[ pre: x > 0 ]]
+{
+  auto *obj = reinterpret_cast<TPL<float> *> (p);
+
+  obj->member = x;
+}
diff --git a/libstdc++-v3/src/c++17/contract.cc b/libstdc++-v3/src/c++17/contract.cc
new file mode 100644
index 00000000000..c13560e4341
--- /dev/null
+++ b/libstdc++-v3/src/c++17/contract.cc
@@ -0,0 +1,136 @@
+// -*- C++ -*- std::contract_violation and friends
+// Copyright (C) 1994-2018 Free Software Foundation, Inc.
+//
+// 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.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <contract>
+#include <exception>
+#include <iostream>
+#include <cstdlib>
+#include <cstdio>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+contract_violation::contract_violation (int line_number,
+  string_view file_name,
+  string_view function_name,
+  string_view comment,
+  string_view assertion_level,
+  string_view assertion_role,
+  contract_violation_continuation_mode continuation_mode)
+  : line_number_(line_number),
+    file_name_(file_name),
+    function_name_(function_name),
+    comment_(comment),
+    assertion_level_(assertion_level),
+    assertion_role_(assertion_role),
+    continuation_mode_(continuation_mode)
+  { }
+
+int
+contract_violation::line_number () const noexcept
+{
+  return this->line_number_;
+}
+
+string_view
+contract_violation::file_name () const noexcept
+{
+  return this->file_name_;
+}
+
+string_view
+contract_violation::function_name () const noexcept
+{
+  return this->function_name_;
+}
+
+string_view
+contract_violation::comment () const noexcept
+{
+  return this->comment_;
+}
+
+string_view
+contract_violation::assertion_level () const noexcept
+{
+  return this->assertion_level_;
+}
+
+string_view
+contract_violation::assertion_role () const noexcept
+{
+  return this->assertion_role_;
+}
+
+contract_violation_continuation_mode
+contract_violation::continuation_mode () const noexcept
+{
+  return this->continuation_mode_;
+}
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+
+__attribute__ ((weak)) void
+handle_contract_violation (const std::contract_violation &violation)
+{
+  std::cerr << "default std::handle_contract_violation called: " << std::endl
+    << " " << violation.file_name()
+    << " " << violation.line_number()
+    << " " << violation.function_name()
+    << " " << violation.comment()
+    << " " << violation.assertion_level()
+    << " " << violation.assertion_role()
+    << " " << (int)violation.continuation_mode()
+    << std::endl;
+}
+
+// We take POD types here to make synthesis easier
+int
+__on_contract_violation (bool continue_,
+                         int line_number,
+                         const char *file_name,
+                         const char *function_name,
+                         const char *comment,
+                         const char *assertion_level,
+                         const char *assertion_role,
+                         int continuation_mode)
+{
+  using cvmc = std::contract_violation_continuation_mode;
+  std::contract_violation violation (line_number,
+				     file_name,
+				     function_name,
+				     comment,
+				     assertion_level,
+				     assertion_role,
+				     static_cast<cvmc>(continuation_mode));
+  handle_contract_violation (violation);
+
+  if (!continue_)
+    std::abort ();
+
+  return 0;
+}
+
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 155be74efdb..f6a21846eef 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -89,7 +89,7 @@ CXX_AND_OBJCXX_OBJS = \
 	cp/call.o cp/class.o cp/constexpr.o cp/constraint.o \
 	cp/coroutines.o cp/cp-gimplify.o \
 	cp/cp-objcp-common.o cp/cp-ubsan.o \
-	cp/cvt.o cp/cxx-pretty-print.o \
+	cp/cvt.o cp/contracts.o cp/cxx-pretty-print.o \
 	cp/decl.o cp/decl2.o cp/dump.o \
 	cp/error.o cp/except.o cp/expr.o \
 	cp/friend.o cp/init.o \
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 725139bb457..c4d8b163622 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -585,6 +585,17 @@ DEFTREECODE (CO_YIELD_EXPR, "co_yield", tcc_expression, 2)
 
 DEFTREECODE (CO_RETURN_EXPR, "co_return", tcc_statement, 2)
 
+/* Different flavors of contracts.
+
+   Assertions and preconditions have two operands: a node containing
+   the their mode and condition. Postconditions have an additional
+   operand to store the optional name for the result value.
+
+   CONTRACT_SEMANTIC has the computed behavior of the contract.  */
+DEFTREECODE (ASSERTION_STMT, "assertion_stmt", tcc_statement, 3)
+DEFTREECODE (PRECONDITION_STMT, "precondition_stmt", tcc_statement, 3)
+DEFTREECODE (POSTCONDITION_STMT, "postcondition_stmt", tcc_statement, 4)
+
 /*
 Local variables:
 mode:c
diff --git a/gcc/testsuite/contracts/backtrace_handler/example_out.txt b/gcc/testsuite/contracts/backtrace_handler/example_out.txt
new file mode 100644
index 00000000000..903ef22f2f5
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/example_out.txt
@@ -0,0 +1,12 @@
+LD_PRELOAD=./libhandle_contract_violation.so ./assert_fail
+contract violation: assert_fail.cpp:3: fun1::x < 0 is false [with contract level=default]
+violation occurs here:
+./assert_fail[0x4011ad]
+./assert_fail[0x4011e0]
+./assert_fail[0x401230]
+./assert_fail[0x4011f1]
+./assert_fail[0x401219]
+/usr/lib/libc.so.6(__libc_start_main+0xf3)[0x7f26e4fa9223]
+./assert_fail[0x4010be]
+[0x0]
+end of violation
diff --git a/gcc/testsuite/contracts/backtrace_handler/example_pretty.txt b/gcc/testsuite/contracts/backtrace_handler/example_pretty.txt
new file mode 100644
index 00000000000..9d5d481a9ef
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/example_pretty.txt
@@ -0,0 +1,8 @@
+LD_PRELOAD=./libhandle_contract_violation.so ./assert_fail
+contract violation: assert_fail.cpp:3: fun1::x < 0 is false [with contract level=default]
+violation occurs here:
+    assert_fail.cpp:fun1():4
+    assert_fail.cpp:tns::fun2():8
+    assert_fail.cpp:void fun3<int>(int):13
+    assert_fail.cpp:fun4():16
+    assert_fail.cpp:main:21
diff --git a/gcc/testsuite/contracts/backtrace_handler/prettytrace.sh b/gcc/testsuite/contracts/backtrace_handler/prettytrace.sh
new file mode 100755
index 00000000000..1978cd1c164
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/prettytrace.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+inViolation="false"
+sed 's/^/:/' /dev/stdin | while read -r line; do
+  line="$(echo "$line" | sed 's/^://')"
+
+  if [[ "${inViolation}" == "false" ]]; then
+    echo "$line"
+    if [[ -n "$(echo "$line" | grep 'violation occurs here:')" ]]; then
+      inViolation="true"
+    fi
+    continue
+  fi
+
+  if [[ -n "$(echo "$line" | grep 'end of violation')" ]]; then
+    inViolation="false"
+    continue
+  fi
+
+  addr="$(echo "$line" | sed -r 's/.*\[0x([a-f0-9]+)\]$/\1/')"
+  bin="$(echo "$line" | sed -r 's/^([^([]*).*/\1/')"
+  [[ -n "${bin}" ]] || continue
+  t="$(addr2line -e "$bin" "$addr" -f)"
+  file="$(echo "$t" | tail -1 | tr ':' '\n' | head -1)"
+  file="$(echo "$file" | sed -r "s:^$(pwd)/?::")"
+  line="$(echo "$t" | tail -1 | tr ':' '\n' | tail -1 | cut -d' ' -f1)"
+  func="$(echo "$t" | head -1 | c++filt)"
+  [[ $file != "??" ]] && echo "    $file:$func:$line"
+done
+
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 5323c7f0604..e4235847b13 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2282,6 +2282,18 @@ GLIBCXX_3.4.26 {
     _ZNSt7codecvtID[is]Du*;
     _ZT[ISV]St7codecvtID[is]Du*E;
 
+    # std::contract_violation::contract_violation (int, std::string_view, std::string_view, std::string_view, std::string_view, std::string_view, std::contract_violation_continuation_mode)
+    _ZNSt18contract_violationC1EiSt17basic_string_viewIcSt11char_traitsIcEES3_S3_S3_S3_St36contract_violation_continuation_mode;
+    _ZNKSt18contract_violation11line_numberEv;
+    _ZNKSt18contract_violation13function_nameEv;
+    _ZNKSt18contract_violation15assertion_levelEv;
+    _ZNKSt18contract_violation14assertion_roleEv;
+    _ZNKSt18contract_violation7commentEv;
+    _ZNKSt18contract_violation9file_nameEv;
+    _ZNKSt18contract_violation17continuation_modeEv;
+
+    _Z25handle_contract_violationRKSt18contract_violation;
+    _Z23__on_contract_violationbiPKcS0_S0_S0_S0_i;
 } GLIBCXX_3.4.25;
 
 GLIBCXX_3.4.27 {
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 40a41ef2a1c..e2599e8fb07 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -39,6 +39,7 @@ std_headers = \
 	${std_srcdir}/complex \
 	${std_srcdir}/concepts \
 	${std_srcdir}/condition_variable \
+	${std_srcdir}/contract \
 	${std_srcdir}/coroutine \
 	${std_srcdir}/deque \
 	${std_srcdir}/execution \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index fcd2b5b2d40..6b5fc80ae88 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -389,6 +389,7 @@ std_headers = \
 	${std_srcdir}/complex \
 	${std_srcdir}/concepts \
 	${std_srcdir}/condition_variable \
+	${std_srcdir}/contract \
 	${std_srcdir}/coroutine \
 	${std_srcdir}/deque \
 	${std_srcdir}/execution \
diff --git a/libstdc++-v3/src/c++17/Makefile.am b/libstdc++-v3/src/c++17/Makefile.am
index cb94aff5f1a..e6337950e39 100644
--- a/libstdc++-v3/src/c++17/Makefile.am
+++ b/libstdc++-v3/src/c++17/Makefile.am
@@ -50,6 +50,7 @@ inst_sources =
 endif
 
 sources = \
+	contract.cc \
 	floating_from_chars.cc \
 	floating_to_chars.cc \
 	fs_dir.cc \
diff --git a/libstdc++-v3/src/c++17/Makefile.in b/libstdc++-v3/src/c++17/Makefile.in
index 63984ecd52a..e4efe8dfc92 100644
--- a/libstdc++-v3/src/c++17/Makefile.in
+++ b/libstdc++-v3/src/c++17/Makefile.in
@@ -124,8 +124,8 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
 libc__17convenience_la_LIBADD =
 @ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-fs_dir.lo cow-fs_ops.lo \
 @ENABLE_DUAL_ABI_TRUE@	cow-fs_path.lo
-am__objects_2 = floating_from_chars.lo floating_to_chars.lo fs_dir.lo \
-	fs_ops.lo fs_path.lo memory_resource.lo $(am__objects_1)
+am__objects_2 = contract.lo floating_from_chars.lo floating_to_chars.lo \
+	fs_dir.lo fs_ops.lo fs_path.lo memory_resource.lo $(am__objects_1)
 @ENABLE_DUAL_ABI_TRUE@am__objects_3 = cow-string-inst.lo
 @ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_4 = ostream-inst.lo \
 @ENABLE_EXTERN_TEMPLATE_TRUE@	string-inst.lo $(am__objects_3)
@@ -439,6 +439,7 @@ headers =
 @ENABLE_EXTERN_TEMPLATE_TRUE@	$(extra_string_inst_sources)
 
 sources = \
+	contract.cc \
 	floating_from_chars.cc \
 	floating_to_chars.cc \
 	fs_dir.cc \
diff --git a/gcc/testsuite/contracts/backtrace_handler/Makefile b/gcc/testsuite/contracts/backtrace_handler/Makefile
new file mode 100644
index 00000000000..4f01a9506a7
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/Makefile
@@ -0,0 +1,13 @@
+CXXFLAGS=--std=c++17 -g
+
+default: assert_fail libhandle_contract_violation.so
+
+run: default
+	LD_PRELOAD=./libhandle_contract_violation.so ./assert_fail
+
+./libhandle_contract_violation.so: ./handle_contract_violation.cpp
+	${CXX} ${CXXFLAGS} -shared -fPIC -o $@ $<
+
+clean:
+	rm -fr ./libhandle_contract_violation.so ./assert_fail
+
diff --git a/gcc/testsuite/contracts/backtrace_handler/README b/gcc/testsuite/contracts/backtrace_handler/README
new file mode 100644
index 00000000000..df729f0d609
--- /dev/null
+++ b/gcc/testsuite/contracts/backtrace_handler/README
@@ -0,0 +1,12 @@
+build and install gcc to $prefix, then to see the raw backtrace info run:
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make run
+
+for a filtered view using addr2line, see ./prettytrace.sh:
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make run |& ./prettytrace.sh
+
+prettytrace.sh relies on addr2line and c++filt to lookup and demangle names,
+and misc coreutils
+
+example_out.txt has an example of the raw output while example_pretty.txt
+shows the corresponding prettified output
+
diff --git a/gcc/testsuite/contracts/except_preload_handler/Makefile b/gcc/testsuite/contracts/except_preload_handler/Makefile
new file mode 100644
index 00000000000..8fcc5b2368a
--- /dev/null
+++ b/gcc/testsuite/contracts/except_preload_handler/Makefile
@@ -0,0 +1,13 @@
+CXXFLAGS=--std=c++17 -fcontract-continuation-mode=on
+
+default: assert_fail libhandle_contract_violation.so
+
+run: default
+	LD_PRELOAD=./libhandle_contract_violation.so ./assert_fail
+
+./libhandle_contract_violation.so: ./handle_contract_violation.cpp
+	${CXX} ${CXXFLAGS} -shared -fPIC -o $@ $<
+
+clean:
+	rm -fr ./*.o ./libhandle_contract_violation.so ./assert_fail
+
diff --git a/gcc/testsuite/contracts/except_preload_handler/README b/gcc/testsuite/contracts/except_preload_handler/README
new file mode 100644
index 00000000000..cbfe48bd33f
--- /dev/null
+++ b/gcc/testsuite/contracts/except_preload_handler/README
@@ -0,0 +1,13 @@
+build and install gcc to $prefix, then run:
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make run
+
+this test has a custom handle_contract_violation that throws an exception
+this test is built with -fcontract-continuation-mode=on
+
+since 1) our fun() is not marked noexcept and 2) the continue mode is set to
+on, we expect the exception thrown within the contract violation handler to
+propagate back up into the catch block located in main()
+
+expected output therefore ends in:
+	synth caught indirect: -1
+
diff --git a/gcc/testsuite/contracts/noexcept_preload_handler/Makefile b/gcc/testsuite/contracts/noexcept_preload_handler/Makefile
new file mode 100644
index 00000000000..8fcc5b2368a
--- /dev/null
+++ b/gcc/testsuite/contracts/noexcept_preload_handler/Makefile
@@ -0,0 +1,13 @@
+CXXFLAGS=--std=c++17 -fcontract-continuation-mode=on
+
+default: assert_fail libhandle_contract_violation.so
+
+run: default
+	LD_PRELOAD=./libhandle_contract_violation.so ./assert_fail
+
+./libhandle_contract_violation.so: ./handle_contract_violation.cpp
+	${CXX} ${CXXFLAGS} -shared -fPIC -o $@ $<
+
+clean:
+	rm -fr ./*.o ./libhandle_contract_violation.so ./assert_fail
+
diff --git a/gcc/testsuite/contracts/noexcept_preload_handler/README b/gcc/testsuite/contracts/noexcept_preload_handler/README
new file mode 100644
index 00000000000..aa7c6dd2df6
--- /dev/null
+++ b/gcc/testsuite/contracts/noexcept_preload_handler/README
@@ -0,0 +1,15 @@
+build and install gcc to $prefix, then run:
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make run
+
+this test has a custom handle_contract_violation that throws an exception
+this test is built with -fcontract-continuation-mode=on
+
+since 1) our fun() *IS* marked noexcept even though 2) the continue mode is
+set to on, we expect the exception thrown within the contract violation
+handler to quashed and have std::terminate run.
+
+expected output therefore ends in:
+	terminate called after throwing an instance of 'int'
+
+despite there being a catch(int &) handler in main
+
diff --git a/gcc/testsuite/contracts/preload_handler/Makefile b/gcc/testsuite/contracts/preload_handler/Makefile
new file mode 100644
index 00000000000..6ff083f4b5c
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_handler/Makefile
@@ -0,0 +1,13 @@
+CXXFLAGS=--std=c++17
+
+default: assert_fail libhandle_contract_violation.so
+
+run: default
+	LD_PRELOAD=./libhandle_contract_violation.so ./assert_fail
+
+./libhandle_contract_violation.so: ./handle_contract_violation.cpp
+	${CXX} ${CXXFLAGS} -shared -fPIC -o $@ $<
+
+clean:
+	rm -fr ./libhandle_contract_violation.so ./assert_fail
+
diff --git a/gcc/testsuite/contracts/preload_handler/README b/gcc/testsuite/contracts/preload_handler/README
new file mode 100644
index 00000000000..cc913fe8188
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_handler/README
@@ -0,0 +1,2 @@
+build and install gcc to $prefix, then run:
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make run
diff --git a/gcc/testsuite/contracts/preload_nocontinue_handler/Makefile b/gcc/testsuite/contracts/preload_nocontinue_handler/Makefile
new file mode 100644
index 00000000000..c8263285471
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_nocontinue_handler/Makefile
@@ -0,0 +1,23 @@
+CXXFLAGS=--std=c++17 -fcontract-continuation-mode=on
+LDFLAGS=-ldl
+
+default: assert_fail libhandle_contract_violation.so libnocontinue.so
+
+run: default
+	./assert_fail
+
+runno: default
+	LD_PRELOAD="./libnocontinue.so ./libhandle_contract_violation.so" ./assert_fail
+
+runnostd: default
+	LD_PRELOAD=./libnocontinue.so ./assert_fail
+
+./libhandle_contract_violation.so: ./handle_contract_violation.cpp
+	${CXX} ${CXXFLAGS} -shared -fPIC -o $@ $<
+
+./libnocontinue.so: ./nocontinue.cpp
+	${CXX} ${CXXFLAGS} -shared -fPIC -o $@ $<
+
+clean:
+	rm -fr ./libhandle_contract_violation.so ./libnocontinue.so ./assert_fail
+
diff --git a/gcc/testsuite/contracts/preload_nocontinue_handler/README b/gcc/testsuite/contracts/preload_nocontinue_handler/README
new file mode 100644
index 00000000000..5c931918759
--- /dev/null
+++ b/gcc/testsuite/contracts/preload_nocontinue_handler/README
@@ -0,0 +1,23 @@
+build and install gcc to $prefix, then run:
+
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make run
+  Build and run with continuation mode on; will print violation info from the
+  standard handler and then continue to print "returning from main"
+
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make runnostd
+  Build and run with continuation mode on, using the default violation handler
+  while preloading the 'nocontinue' hook. This uses LD_PRELOAD to turn all
+  continuing contract violations into non-continuing versions.
+
+  Will print violation info from the standard handler and then terminate -- it
+  will not print "returning from main"
+
+LD_LIBRARY_PATH=$prefix/lib64 CXX=$prefix/bin/g++ make runno
+  Build and run with continuation mode on, using a custom violation handler
+  while preloading the 'nocontinue' hook. This uses LD_PRELOAD to turn all
+  continuing contract violations into non-continuing versions and to install a
+  custom violation handler.
+
+  Will print violation info from the custom handler and then terminate -- it
+  will not print "returning from main"
+
diff --git a/libstdc++-v3/include/std/contract b/libstdc++-v3/include/std/contract
new file mode 100644
index 00000000000..039a8e24a12
--- /dev/null
+++ b/libstdc++-v3/include/std/contract
@@ -0,0 +1,76 @@
+// Contracts support header for -*- C++ -*-
+
+// Copyright (C) 1995-2018 Free Software Foundation, Inc.
+//
+// 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.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file contract
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_CONTRACT
+#define _GLIBCXX_CONTRACT 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201703L
+
+#include <bits/c++config.h>
+#include <string_view>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  enum class contract_violation_continuation_mode {
+    NEVER_CONTINUE, MAYBE_CONTINUE
+  };
+
+  class contract_violation {
+    int line_number_;
+    string_view file_name_;
+    string_view function_name_;
+    string_view comment_;
+    string_view assertion_level_;
+    string_view assertion_role_;
+    contract_violation_continuation_mode continuation_mode_;
+  public:
+    contract_violation (int, string_view, string_view, string_view, string_view,
+                        string_view, contract_violation_continuation_mode);
+    int line_number() const noexcept;
+    string_view file_name() const noexcept;
+    string_view function_name() const noexcept;
+    string_view comment() const noexcept;
+    string_view assertion_level() const noexcept;
+    string_view assertion_role() const noexcept;
+    contract_violation_continuation_mode continuation_mode() const noexcept;
+  };
+
+  //void handle_contract_violation (const contract_violation &);
+
+  //int on_contract_violation (bool, int, const char *, const char *, const char *, const char *, const char *, int);
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+#endif // _GLIBCXX_CONTRACT


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-07-06 20:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-06 20:43 [gcc/devel/c++-contracts] c++: implement P1492 contracts Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).