public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] implement pre-c++20 contracts
@ 2019-11-13 19:23 Jeff Chapman
  2019-12-10  5:58 ` Jason Merrill
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Chapman @ 2019-11-13 19:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Andrew Sutton

[-- Attachment #1: Type: text/plain, Size: 5022 bytes --]

Hello,

Attached is a patch that implements pre-c++20 contracts. This comes
from a long running development branch which included ChangeLog entries
as we went, which are included in the patch itself. The repo and
initial wiki are located here:
https://gitlab.com/lock3/gcc-new/wikis/GCC-with-Contracts

We've previously circulated a paper (P1680) which documents our
implementation experience which largely covers new flags and features.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1680r0.pdf

That paper documents our changes in depth, barring the recently added
-fcontracts flag which is a global opt-in for contracts functionality.
As an overview of what we've done is included below for convenience.

The following switches have been added:

-fcontracts
  enable contract features in general

Flags from the old Working Draft:

-fcontract-build-level=[off|default|audit]
  specify max contract level to generate runtime checks for

-fcontract-continuation-mode=[on|off]
  toggle whether execution resumes after contract failure

Flags from P1290:

-fcontract-assumption-mode=[on|off]
  enable treating axiom level contracts as compile time assumptions
  (default on)

Flags from P1429:

-fcontract-mode=[on|off]
  enable or disable all contract facilities (default on)

-fcontract-semantic=<level>:<semantic>
  specify the concrete semantics for a level

Flags from P1332:

-fcontract-role=<name>:<semantics>
  specify semantics for all levels in a role (default, review, or a
    custom role)
  (ex: opt:assume,assume,assume)

Additional flags:

-fcontract-strict-declarations=[on|off]
  toggle warnings on generalized redecl of member functions
    without contracts (default off)


One assert contract may be present on any block scope empty statement:
  [[ assert contract-mode_opt : conditional-expression ]]

Function declarations have an optional, ordered, list of pre and post
contracts:
  [[ pre contract-mode_opt : conditional-expression ]]
  [[ post contract-mode_opt identifier_opt : conditional-expression ]]


The grammar for the contract-mode_opt portion which configures the
concrete semantics of the contracts is:

contract-mode
  contract-semantic
  contract-level_opt contract-role_opt

contract-semantic
  ignore
  check_never_continue
  check_maybe_continue
  check_always_continue
  assume

contract-level
  default
  audit
  axiom

contract-role
  %default
  %identifier


Contracts are configured via concrete semantics or by an optional
level and role which map to one of the concrete semantics:

  ignore – The contract does not affect the behavior of the program.
  assume – The condition may be used for optimization.
  never_continue – The program terminates if the contract is
                   not satisfied.
  maybe_continue – A user-defined violation handler may terminate the
                   program.
  always_continue – The program continues even if the contract is not
                    satisfied.


-fcontracts enables generalized member function redeclaration. That is,
non-defining declarations of member functions are allowed outside the
initial class definition.

Contracts are not required on the initial declaration of a
(non-virtual) function as long as all TUs that see a set of contracts
eventually see the same set of contracts. All contracts must be present
on the first declaration for virtual functions to ensure we know to
split the function in all overrides.


Explicit template specializations have an independent set of contracts
than any other explicit specializations.


Functions with contracts (which we call guarded functions) are split
just before genericization. A wrapper which checks pre and post
contracts is emitted with the original function name, while the
original function body is emitted under a new unchecked name. This
means that calls to functions in TUs which never see the contract list
still call a checked version of the function (see insulated contracts
in P1680).

Having a checked and unchecked version of the function makes it
potentially easier to inline the checks into the caller, and prevents
the need to repeat the post contracts at all return statements in the
original function.


A custom contract violation handler can be installed by defining
  void handle_contract_violation(const std::contract_violation &)

(you must #include <contract> for this to work) or by using LD_PRELOAD.
An example of defining the handler in the main TU can be found in the
testsuite g++.dg/cpp2a/contracts16.C .

Examples of how to use LD_PRELOAD to install a custom violation handler
are available in the contracts folder inside the testsuite.


Bootstrapped and tested on x86_64-pc-linux-gnu. cmcstl2 compiles cleanly
and has no `make test` failures.


Please let me know if you have any questions or know what the next
steps will be.


Thank you,
Jeff Chapman II

[-- Attachment #2: 0001-Implement-pre-c-20-contracts.patch.gz --]
[-- Type: application/gzip, Size: 95619 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2019-11-13 19:23 [PATCH] implement pre-c++20 contracts Jeff Chapman
@ 2019-12-10  5:58 ` Jason Merrill
  2019-12-10  6:20   ` Jason Merrill
                     ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Jason Merrill @ 2019-12-10  5:58 UTC (permalink / raw)
  To: Jeff Chapman, gcc-patches; +Cc: Andrew Sutton

On 11/13/19 2:07 PM, Jeff Chapman wrote:
> Attached is a patch that implements pre-c++20 contracts. This comes
> from a long running development branch which included ChangeLog entries
> as we went, which are included in the patch itself. The repo and
> initial wiki are located here:
> https://gitlab.com/lock3/gcc-new/wikis/GCC-with-Contracts

Thanks.  I've mostly been referring to the repo rather than the attached 
patch.  Below are a bunch of comments about the implementation, in no 
particular order.

> We've previously circulated a paper (P1680) which documents our
> implementation experience which largely covers new flags and features.
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1680r0.pdf
> 
> That paper documents our changes in depth, barring the recently added
> -fcontracts flag which is a global opt-in for contracts functionality.
> As an overview of what we've done is included below for convenience.
> 
> The following switches have been added:
> 
> -fcontracts
>    enable contract features in general
> 
> Flags from the old Working Draft:
> 
> -fcontract-build-level=[off|default|audit]
>    specify max contract level to generate runtime checks for
> 
> -fcontract-continuation-mode=[on|off]
>    toggle whether execution resumes after contract failure
> 
> Flags from P1290:
> 
> -fcontract-assumption-mode=[on|off]
>    enable treating axiom level contracts as compile time assumptions
>    (default on)
> 
> Flags from P1429:
> 
> -fcontract-mode=[on|off]
>    enable or disable all contract facilities (default on)
> 
> -fcontract-semantic=<level>:<semantic>
>    specify the concrete semantics for a level
> 
> Flags from P1332:
> 
> -fcontract-role=<name>:<semantics>
>    specify semantics for all levels in a role (default, review, or a
>      custom role)
>    (ex: opt:assume,assume,assume)
> 
> Additional flags:
> 
> -fcontract-strict-declarations=[on|off]
>    toggle warnings on generalized redecl of member functions
>      without contracts (default off)
> 
> 
> One assert contract may be present on any block scope empty statement:
>    [[ assert contract-mode_opt : conditional-expression ]]
> 
> Function declarations have an optional, ordered, list of pre and post
> contracts:
>    [[ pre contract-mode_opt : conditional-expression ]]
>    [[ post contract-mode_opt identifier_opt : conditional-expression ]]
> 
> 
> The grammar for the contract-mode_opt portion which configures the
> concrete semantics of the contracts is:
> 
> contract-mode
>    contract-semantic
>    contract-level_opt contract-role_opt
> 
> contract-semantic
>    ignore
>    check_never_continue
>    check_maybe_continue
>    check_always_continue
>    assume
> 
> contract-level
>    default
>    audit
>    axiom
> 
> contract-role
>    %default
>    %identifier
> 
> 
> Contracts are configured via concrete semantics or by an optional
> level and role which map to one of the concrete semantics:
> 
>    ignore – The contract does not affect the behavior of the program.
>    assume – The condition may be used for optimization.
>    never_continue – The program terminates if the contract is
>                     not satisfied.
>    maybe_continue – A user-defined violation handler may terminate the
>                     program.
>    always_continue – The program continues even if the contract is not
>                      satisfied.

I find the proposed always_continue semantics kind of nonsensical, as 
somewhat evidenced by the contortions the implementation gets into with 
marking the violation handler as pure.  The trick of assigning the 
result to a local variable won't work with optimization.

It also depends on the definition of a function that can be overridden 
to in fact never return.  This seems pretty fatal to it ever getting 
into the standard.

It's also unclear to me why anyone would want the described semantics. 
Why would you want a contract check that can be optimized away due to 
later undefined behavior?  The 0.2 use case from P1332 seems better 
suited to maybe_continue, because with always_continue such a check will 
have false negatives, leading to an unpleasant surprise when switching 
to never_continue.

I'd prefer to treat always_continue as equivalent to maybe_continue. 
Perhaps with ECF_NOTHROW|ECF_LEAF|ECF_NOVOPS to indicate that it doesn't 
clobber anything the caller can see, but that's risky if the handler is 
in fact defined in the same TU with anything that uses contracts.

> +  if (strcmp (name, "check_always_continue") == 0
> +      || strcmp (name, "always") == 0
> +      || strcmp (name, "continue") == 0)

Accordingly, "continue" should mean maybe_continue.

> +/* Definitions for C++ contract levels
> +   Copyright (C) 1987-2018 Free Software Foundation, Inc.

Should just be 2019 for a new file.

> +   Contributed by Michael Tiemann (tiemann@cygnus.com)

This seems inaccurate.  :)

It would also be good to have a reference to P1332 in this header.

> +/* Assertion role info.
> +
> +   FIXME: Why is this prefixed cpp?  */
> +struct cpp_contract_role

There seems to be no reason for it, since the struct definition is 
followed by a typedef; let's remove the prefix.

Any cpp_ prefixes we want to keep should change to cxx to avoid 
ambiguity with the preprocessor.

> +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");

Hmm, P1429 includes the notion of build level, it's just checked after 
explicit semantics.  In general, P1429 seems like a compatible extension 
of the semantics previously in the working paper.

P1332 could also be treated as compatible if we consider the P0542 build 
level to affect the default role as specified in P1429.  P1680 seems to 
suggest that this is what you had in mind.

> +  // TODO: worry about leaking this?
> +  char *name = xstrdup (arg);

Yes, worry. :)
There's no reason to leak it.

> +++ b/gcc/c-family/contract.c
> @@ -0,0 +1,138 @@
> +#include "config.h"
> +#include "system.h"

This file needs the introductory copyright block.  It should probably be 
named cxx-contracts.c.  Can more of the option handling move into this file?

> +  return (contract_semantic) CONTRACT_CHECK (t)->base.u.bits.spare1;
> +  CONTRACT_CHECK (t)->base.u.bits.spare1 = semantic;

You can't use spare* for data; they are only for allocating bits out of 
for other named fields.  You could encode the semantic into multiple 
TREE_LANG_FLAG_* or make it an operand of the expression.

> @@ -2730,6 +2809,13 @@ struct GTY(()) lang_decl_fn {
>      tree GTY ((tag ("0"))) saved_auto_return_type;
>    } GTY ((desc ("%1.pending_inline_p"))) u;
>  
> +  /* For the checked version of a guarded function, this points to the var
> +     caputring the result of the unchecked function.  */
> +  tree unchecked_result;
> +  /* For a guarded function with contracts, this is a tree list where
> +     the purpose is the location of the contracts and the value is the list of
> +     contracts specified in original decl order.  */
> +  tree contracts;
>  };

Let's not make all functions two words larger to support contracts; this 
information can go either in an attribute or a separate hash table.  An 
attribute seems natural for the contracts since that's already the 
syntax contracts use.  I wouldn't expect you to need a pointer to the 
unchecked result in the FUNCTION_DECL, that seems like a detail local to 
the implementation of the checked function.

> @@ -6036,6 +6157,8 @@ struct cp_declarator {
>       declarator is a pointer or a reference, these attributes apply
>       to the pointer, rather than to the type pointed to.  */
>    tree std_attributes;
> +  /* The contracts, if any. */
> +  tree contracts;

Adding to cp_declarator isn't a problem, but again it seems like 
contracts could be represented as attributes.  In general, it seems like 
you are working to subvert the attribute mechanisms rather than using 
them normally, and I'm not sure why.

> +  /* Check that assertions are null statements.  */
> +  if (attribute_contract_assert_p (contract_attrs))
> +    if (token->type != CPP_SEMICOLON)
> +      error_at (token->location, "assertions must be followed by %<;%>");

Better I think to handle this further down where [[fallthrough]] has the 
same requirement.

> +++ b/gcc/c-family/c-common.c
> @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "spellcheck.h"
>  #include "c-spellcheck.h"
>  #include "selftest.h"
> +#include "print-tree.h"

I don't see anything that needs this.

> +  /* Compare the conditions of the contracts.  */
> +  tree old_cond = cp_fully_fold_init (CONTRACT_CONDITION (old_contract));
> +  tree new_cond = cp_fully_fold_init (CONTRACT_CONDITION (new_contract));
> +  if (!cp_tree_equal (old_cond, new_cond))

Why fold before comparison?  I would think that we want the conditions 
to be equivalent before folding.

> +/* Compare the contract attributes of OLDDECL and NEWDECL. Returns false 
> +   if the contracts match, and true if they differ.  */
> +
> +static bool
> +match_contract_conditions (location_t oldloc, tree old_attrs,
...
> +match_contracts (tree olddecl, location_t newloc, tree new_attrs)

These names suggest to me that they would return true if they match, 
rather than true if there's a problem.  Changing "match" to "mismatched" 
would be better.

>        if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
>           /* Aliases are definitions. */
> -         && !alias)
> +         && !alias
> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>         permerror (declarator->id_loc,
>                    "declaration of %q#D outside of class is not definition",
>                    decl);
> +      else if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
> +         /* Aliases are definitions. */
> +         && !alias
> +         && flag_contract_strict_declarations)
> +       warning_at (declarator->id_loc, OPT_fcontract_strict_declarations_,
> +                   "non-defining declaration of %q#D outside of class", decl);

This change to member function redeclaration seems undesirable; your 
rationale in P1680 is "for generality", but member functions are already 
stricter about redeclaration than non-member functions; I don't see a 
reason to relax this rule just for contracts.  With member functions, 
there *is* always a canonical first declaration, and people expect the 
class definition to have its complete interface, of which contracts are 
a part.

For non-member functions, we still need to complain if contracts are 
added after we've seen an ODR-use of the function, just like with 
explicit specializations.

> +      /* TODO is there any way to relax this requirement?  */
> +      if (DECL_VIRTUAL_P (olddecl) && !TYPE_BEING_DEFINED (DECL_CONTEXT (olddecl)))

Relatedly, I don't think we want to relax this requirement.

> +  /* FIXME part of this is taken from store_parm_decls -- is there an existing
> +     method that does only this subset of work?  */

I think you're looking for inject_parm_decls; that's what deferred 
noexcept parsing uses.

> +  /* If we're entering a class member; ensure current_class_ptr and
> +     current_class_ref point to the correct place.  */

And this is inject_this_parameter.

> +/* Build and return a new string representing the unchecked function name
> +   corresponding to the name in IDENT. */
> +
> +// FIXME: are we sure we shouldn't just mangle or use some existing machinery?
> +static const char *
> +get_contracts_internal_decl_name (const char *ident)

You absolutely should use the mangler, and should propose a mangling to 
the ABI committee at https://github.com/itanium-cxx-abi/cxx-abi/issues

For comparison, transactional memory extra entry points are encoded by 
inserting "GTt" after the _Z in the mangling of a function; something 
similar seems appropriate here.

> +/* Like copy_fn; rebuild UNCHECKED's DECL_SAVED_TREE to have its own locals
> +   and point to its own DECL_ARGUMENTS and DECL_RESULT instead of pointing at
> +   CHECKED's.
> +
> +   Unlike copy_fn, UNCHECKED (the target) does not need to be
> +   current_function_decl.  */

Why not leave the function the user declared as the unchecked function 
(just changing some linkage properties) and create a new function for 
the checked wrapper?

> +         && (declarator->kind != cdk_function
> +             || !inner_declarator || inner_declarator->kind != cdk_id))

I think you want function_declarator_p.

> +  // TODO: can this contextually be ECF_NOTHROW if inside a noexcept?

That doesn't sound worthwhile to me.

> +/* Parse a conditional-expression.  */
> +/* FIXME: should callers use cp_parser_constant_expression?  */

It doesn't really matter since C++11 generalized constant expressions; 
we don't need to enforce their rules in the parser anymore.

> +/* Return the source text between two locations.  */
> +
> +static char *
> +get_source (location_t start, location_t end)

This seems like it belongs in libcpp.  It also needs to

> +  /* FIXME how should we handle newlines and runs of spaces?  */
> +  char buf[1024 + 4]{};
> +  char *res = buf;
> +  size_t len = 1024;

Obstacks work very well for temporary buffers like this.

> +/* Pretty print an expression and return the result as a char*.  */
> +
> +static char*
> +stringify_tree (tree expr)

Is there a reason not to use expr_to_string?

> +  /* TODO: If this is a postcondition and the return type is deduced,
> +     then we need to cache tokens and parse when the function is
> +     defined.

Yes.

> +     Would it be okay to declare the result decl as having a deduced
> +     return type also?

For a template, yes.  For a non-templated function, no.

> +     NOTE: You can't declare a deduced return type function with
> +     postconditions and not define it.  */

Well, you can, but you can't call it, so it doesn't matter if we haven't 
figured out the contracts.

> +   FIXME: There are probably earlier exits than end of file. What
> +   about a semicolon?  */

You could use cp_parser_skip_to_closing_parenthesis_1 to look for an 
un-nested ] and then complain if it isn't followed by another ].

> +/* 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. */

You will want to use forward_parm in this function.

> +      if (VOID_TYPE_P (t))
> +       continue;

There are no void parameters in DECL_ARGUMENTS (only in TYPE_ARG_TYPES).

> +      error ("guarded function %q+D overriding non-guarded function",

The term "guarded" doesn't seem to appear in any of the contracts papers 
other than yours, so let's word this differently.

> +      error ("guarded function %q+D overriding non-guarded function",
> +            overrider);
> +      inform (DECL_SOURCE_LOCATION (basefn),
> +             "overridden function is %qD", basefn);
> +      return 0; // FIXME?

What's to fix?

> +  /* FIXME: Why do we have two unrelated statement lists?  */
> +  tree def = push_stmt_list();
> +  tree body = begin_compound_stmt (BCS_NORMAL);

You probably want begin_function_body instead of push_stmt_list.

> +  finish_function_body (TREE_VALUE (def));

And then a finish_compound_stmt before the finish_function_body.

> +  /* FIXME we're marking the unchecked fn decl as not virtual, so why do we
> +     need to disallow virtual when building the call? */

Indeed, the disallow_virtual argument only matters for virtual 
functions, so either value is fine.

> +  /* FIXME it may make more sense to have the checked function be concrete
> +     with the unchecked be virtual since all checked function overrides must
> +     be equivalent due to the contract matching requirement.  */

Doing it that way would allow better inlining of the checking wrapper, 
but would require some way to specify virtual or non-virtual calling 
from the checking wrapper to the unchecked function.

> +  /* FIXME temporarily inlined from finish_compound_stmt except for actually
> +     adding the compound statement to the current statement list. We need
> +     several parts of this logic to handle normal and template parsing for
> +     postconditions, but is there something better we can use instead?  */

You could push/pop_stmt_list around the call to finish_compound_stmt to 
capture the result.

> +  tree level_str = build_string_literal (strlen (level) + 1, level);
> +  tree role_str = build_string_literal (strlen (role) + 1, role);

Maybe combine these into a single string argument?

> +  /* We never want to accidentally instantiate templates.  */
> +  if (code == TEMPLATE_DECL)
> +    return *tp; /* FIXME? */

This seems unlikely to have the desired effect; we should see template 
instantiations as FUNCTION_DECL or VAR_DECL.  I'm also not sure what the 
cp_tree_defined_p check is trying to do; surely using defined functions 
and variables can also lead to runtime code?

> +  /* FIXME: This code gen will be moved to gimple.  */

It should be simple enough to move to cp_genericize_r.

> +  /* The condition is converted to bool.
> +
> +     FIXME: When we instantiate this, the input location is in entirely
> +     the wrong place.  */

It should work to attach the location to the contract _STMT.

> @@ -14156,6 +14156,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>               goto dont_recalculate;
>  
>             default:
> +              debug_tree (*expr_p);

Leftover debugging code.

> +      /* If we don't have contracts and haven't already set the deferred
> +        contracts to a "no initial contracts" sentinel, do so now to support
> +        flag_contract_strict_declarations.  */

What is the advantage of this sentinel over NULL_TREE?

> +// TODO FIXME override stops parsing of attrs silently?

Any more information about this?

> +    /* FIXME: should the contracts on a friend decl be a complete class
> +       context for the type being currently defined? */
> +  /* FIXME contracts can be parsed inside of a class when the decl is a friend? */

I would expect all contract attributes in a class to be complete class 
contexts, whether the function is a member or friend.

> +  /* FIXME Is this right for friends? Can a friend refer to a static member?
> +     Can a friend's contracts refer to our privates? Turning them into
> +     [[assert]]s inside the body of the friend itself certainly lets them do
> +     so. */

P0542 says contracts are limited to the accessibility of the function 
itself, so a friend cannot refer to private members.

> +  /* FIXME Do instantiations mean anything in the context of contracts?  */

No; I'm not sure what they mean for default arguments.

> +      DECL_DEFERRED_CONTRACTS (decl) = chainon (
> +         DECL_DEFERRED_CONTRACTS (decl),
> +         build_tree_list (original_loc, fn->contracts));

This indentation pattern occurs pretty often in the patch, but doesn't 
match the usual style in GCC sources; there's only one occurrence of a 
left paren at the end of a line.  Please move it to the beginning of the 
argument list on the next line.  The following lines also seem more 
indented than necessary.

Jason

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2019-12-10  5:58 ` Jason Merrill
@ 2019-12-10  6:20   ` Jason Merrill
  2020-03-24 14:23   ` Andrew Sutton
  2020-05-07 15:56   ` Jeff Chapman
  2 siblings, 0 replies; 31+ messages in thread
From: Jason Merrill @ 2019-12-10  6:20 UTC (permalink / raw)
  To: Jeff Chapman, gcc-patches; +Cc: Andrew Sutton

On 12/10/19 12:58 AM, Jason Merrill wrote:
> On 11/13/19 2:07 PM, Jeff Chapman wrote:
>> Attached is a patch that implements pre-c++20 contracts. This comes
>> from a long running development branch which included ChangeLog entries
>> as we went, which are included in the patch itself. The repo and
>> initial wiki are located here:
>> https://gitlab.com/lock3/gcc-new/wikis/GCC-with-Contracts
> 
> Thanks.  I've mostly been referring to the repo rather than the attached 
> patch.  Below are a bunch of comments about the implementation, in no 
> particular order.
> 
>> We've previously circulated a paper (P1680) which documents our
>> implementation experience which largely covers new flags and features.
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1680r0.pdf
>>
>> That paper documents our changes in depth, barring the recently added
>> -fcontracts flag which is a global opt-in for contracts functionality.
>> As an overview of what we've done is included below for convenience.
>>
>> The following switches have been added:
>>
>> -fcontracts
>>    enable contract features in general
>>
>> Flags from the old Working Draft:
>>
>> -fcontract-build-level=[off|default|audit]
>>    specify max contract level to generate runtime checks for
>>
>> -fcontract-continuation-mode=[on|off]
>>    toggle whether execution resumes after contract failure
>>
>> Flags from P1290:
>>
>> -fcontract-assumption-mode=[on|off]
>>    enable treating axiom level contracts as compile time assumptions
>>    (default on)
>>
>> Flags from P1429:
>>
>> -fcontract-mode=[on|off]
>>    enable or disable all contract facilities (default on)
>>
>> -fcontract-semantic=<level>:<semantic>
>>    specify the concrete semantics for a level
>>
>> Flags from P1332:
>>
>> -fcontract-role=<name>:<semantics>
>>    specify semantics for all levels in a role (default, review, or a
>>      custom role)
>>    (ex: opt:assume,assume,assume)
>>
>> Additional flags:
>>
>> -fcontract-strict-declarations=[on|off]
>>    toggle warnings on generalized redecl of member functions
>>      without contracts (default off)
>>
>>
>> One assert contract may be present on any block scope empty statement:
>>    [[ assert contract-mode_opt : conditional-expression ]]
>>
>> Function declarations have an optional, ordered, list of pre and post
>> contracts:
>>    [[ pre contract-mode_opt : conditional-expression ]]
>>    [[ post contract-mode_opt identifier_opt : conditional-expression ]]
>>
>>
>> The grammar for the contract-mode_opt portion which configures the
>> concrete semantics of the contracts is:
>>
>> contract-mode
>>    contract-semantic
>>    contract-level_opt contract-role_opt
>>
>> contract-semantic
>>    ignore
>>    check_never_continue
>>    check_maybe_continue
>>    check_always_continue
>>    assume
>>
>> contract-level
>>    default
>>    audit
>>    axiom
>>
>> contract-role
>>    %default
>>    %identifier
>>
>>
>> Contracts are configured via concrete semantics or by an optional
>> level and role which map to one of the concrete semantics:
>>
>>    ignore – The contract does not affect the behavior of the program.
>>    assume – The condition may be used for optimization.
>>    never_continue – The program terminates if the contract is
>>                     not satisfied.
>>    maybe_continue – A user-defined violation handler may terminate the
>>                     program.
>>    always_continue – The program continues even if the contract is not
>>                      satisfied.
> 
> I find the proposed always_continue semantics kind of nonsensical, as 
> somewhat evidenced by the contortions the implementation gets into with 
> marking the violation handler as pure.  The trick of assigning the 
> result to a local variable won't work with optimization.
> 
> It also depends on the definition of a function that can be overridden 
> to in fact never return.  This seems pretty fatal to it ever getting 
> into the standard.
> 
> It's also unclear to me why anyone would want the described semantics. 
> Why would you want a contract check that can be optimized away due to 
> later undefined behavior?  The 0.2 use case from P1332 seems better 
> suited to maybe_continue, because with always_continue such a check will 
> have false negatives, leading to an unpleasant surprise when switching 
> to never_continue.
> 
> I'd prefer to treat always_continue as equivalent to maybe_continue. 
> Perhaps with ECF_NOTHROW|ECF_LEAF|ECF_NOVOPS to indicate that it doesn't 
> clobber anything the caller can see, but that's risky if the handler is 
> in fact defined in the same TU with anything that uses contracts.
> 
>> +  if (strcmp (name, "check_always_continue") == 0
>> +      || strcmp (name, "always") == 0
>> +      || strcmp (name, "continue") == 0)
> 
> Accordingly, "continue" should mean maybe_continue.
> 
>> +/* Definitions for C++ contract levels
>> +   Copyright (C) 1987-2018 Free Software Foundation, Inc.
> 
> Should just be 2019 for a new file.
> 
>> +   Contributed by Michael Tiemann (tiemann@cygnus.com)
> 
> This seems inaccurate.  :)
> 
> It would also be good to have a reference to P1332 in this header.
> 
>> +/* Assertion role info.
>> +
>> +   FIXME: Why is this prefixed cpp?  */
>> +struct cpp_contract_role
> 
> There seems to be no reason for it, since the struct definition is 
> followed by a typedef; let's remove the prefix.
> 
> Any cpp_ prefixes we want to keep should change to cxx to avoid 
> ambiguity with the preprocessor.
> 
>> +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");
> 
> Hmm, P1429 includes the notion of build level, it's just checked after 
> explicit semantics.  In general, P1429 seems like a compatible extension 
> of the semantics previously in the working paper.
> 
> P1332 could also be treated as compatible if we consider the P0542 build 
> level to affect the default role as specified in P1429.  P1680 seems to 
> suggest that this is what you had in mind.
> 
>> +  // TODO: worry about leaking this?
>> +  char *name = xstrdup (arg);
> 
> Yes, worry. :)
> There's no reason to leak it.
> 
>> +++ b/gcc/c-family/contract.c
>> @@ -0,0 +1,138 @@
>> +#include "config.h"
>> +#include "system.h"
> 
> This file needs the introductory copyright block.  It should probably be 
> named cxx-contracts.c.  Can more of the option handling move into this 
> file?
> 
>> +  return (contract_semantic) CONTRACT_CHECK (t)->base.u.bits.spare1;
>> +  CONTRACT_CHECK (t)->base.u.bits.spare1 = semantic;
> 
> You can't use spare* for data; they are only for allocating bits out of 
> for other named fields.  You could encode the semantic into multiple 
> TREE_LANG_FLAG_* or make it an operand of the expression.
> 
>> @@ -2730,6 +2809,13 @@ struct GTY(()) lang_decl_fn {
>>      tree GTY ((tag ("0"))) saved_auto_return_type;
>>    } GTY ((desc ("%1.pending_inline_p"))) u;
>>
>> +  /* For the checked version of a guarded function, this points to 
>> the var
>> +     caputring the result of the unchecked function.  */
>> +  tree unchecked_result;
>> +  /* For a guarded function with contracts, this is a tree list where
>> +     the purpose is the location of the contracts and the value is 
>> the list of
>> +     contracts specified in original decl order.  */
>> +  tree contracts;
>>  };
> 
> Let's not make all functions two words larger to support contracts; this 
> information can go either in an attribute or a separate hash table.  An 
> attribute seems natural for the contracts since that's already the 
> syntax contracts use.  I wouldn't expect you to need a pointer to the 
> unchecked result in the FUNCTION_DECL, that seems like a detail local to 
> the implementation of the checked function.
> 
>> @@ -6036,6 +6157,8 @@ struct cp_declarator {
>>       declarator is a pointer or a reference, these attributes apply
>>       to the pointer, rather than to the type pointed to.  */
>>    tree std_attributes;
>> +  /* The contracts, if any. */
>> +  tree contracts;
> 
> Adding to cp_declarator isn't a problem, but again it seems like 
> contracts could be represented as attributes.  In general, it seems like 
> you are working to subvert the attribute mechanisms rather than using 
> them normally, and I'm not sure why.
> 
>> +  /* Check that assertions are null statements.  */
>> +  if (attribute_contract_assert_p (contract_attrs))
>> +    if (token->type != CPP_SEMICOLON)
>> +      error_at (token->location, "assertions must be followed by 
>> %<;%>");
> 
> Better I think to handle this further down where [[fallthrough]] has the 
> same requirement.
> 
>> +++ b/gcc/c-family/c-common.c
>> @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3.  If not see
>>  #include "spellcheck.h"
>>  #include "c-spellcheck.h"
>>  #include "selftest.h"
>> +#include "print-tree.h"
> 
> I don't see anything that needs this.
> 
>> +  /* Compare the conditions of the contracts.  */
>> +  tree old_cond = cp_fully_fold_init (CONTRACT_CONDITION 
>> (old_contract));
>> +  tree new_cond = cp_fully_fold_init (CONTRACT_CONDITION 
>> (new_contract));
>> +  if (!cp_tree_equal (old_cond, new_cond))
> 
> Why fold before comparison?  I would think that we want the conditions 
> to be equivalent before folding.
> 
>> +/* Compare the contract attributes of OLDDECL and NEWDECL. Returns 
>> false +   if the contracts match, and true if they differ.  */
>> +
>> +static bool
>> +match_contract_conditions (location_t oldloc, tree old_attrs,
> ...
>> +match_contracts (tree olddecl, location_t newloc, tree new_attrs)
> 
> These names suggest to me that they would return true if they match, 
> rather than true if there's a problem.  Changing "match" to "mismatched" 
> would be better.
> 
>>        if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
>>           /* Aliases are definitions. */
>> -         && !alias)
>> +         && !alias
>> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>>         permerror (declarator->id_loc,
>>                    "declaration of %q#D outside of class is not 
>> definition",
>>                    decl);
>> +      else if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION 
>> (decl)
>> +         /* Aliases are definitions. */
>> +         && !alias
>> +         && flag_contract_strict_declarations)
>> +       warning_at (declarator->id_loc, 
>> OPT_fcontract_strict_declarations_,
>> +                   "non-defining declaration of %q#D outside of 
>> class", decl);
> 
> This change to member function redeclaration seems undesirable; your 
> rationale in P1680 is "for generality", but member functions are already 
> stricter about redeclaration than non-member functions; I don't see a 
> reason to relax this rule just for contracts.  With member functions, 
> there *is* always a canonical first declaration, and people expect the 
> class definition to have its complete interface, of which contracts are 
> a part.
> 
> For non-member functions, we still need to complain if contracts are 
> added after we've seen an ODR-use of the function, just like with 
> explicit specializations.
> 
>> +      /* TODO is there any way to relax this requirement?  */
>> +      if (DECL_VIRTUAL_P (olddecl) && !TYPE_BEING_DEFINED 
>> (DECL_CONTEXT (olddecl)))
> 
> Relatedly, I don't think we want to relax this requirement.
> 
>> +  /* FIXME part of this is taken from store_parm_decls -- is there an 
>> existing
>> +     method that does only this subset of work?  */
> 
> I think you're looking for inject_parm_decls; that's what deferred 
> noexcept parsing uses.
> 
>> +  /* If we're entering a class member; ensure current_class_ptr and
>> +     current_class_ref point to the correct place.  */
> 
> And this is inject_this_parameter.
> 
>> +/* Build and return a new string representing the unchecked function 
>> name
>> +   corresponding to the name in IDENT. */
>> +
>> +// FIXME: are we sure we shouldn't just mangle or use some existing 
>> machinery?
>> +static const char *
>> +get_contracts_internal_decl_name (const char *ident)
> 
> You absolutely should use the mangler, and should propose a mangling to 
> the ABI committee at https://github.com/itanium-cxx-abi/cxx-abi/issues
> 
> For comparison, transactional memory extra entry points are encoded by 
> inserting "GTt" after the _Z in the mangling of a function; something 
> similar seems appropriate here.
> 
>> +/* Like copy_fn; rebuild UNCHECKED's DECL_SAVED_TREE to have its own 
>> locals
>> +   and point to its own DECL_ARGUMENTS and DECL_RESULT instead of 
>> pointing at
>> +   CHECKED's.
>> +
>> +   Unlike copy_fn, UNCHECKED (the target) does not need to be
>> +   current_function_decl.  */
> 
> Why not leave the function the user declared as the unchecked function 
> (just changing some linkage properties) and create a new function for 
> the checked wrapper?
> 
>> +         && (declarator->kind != cdk_function
>> +             || !inner_declarator || inner_declarator->kind != cdk_id))
> 
> I think you want function_declarator_p.
> 
>> +  // TODO: can this contextually be ECF_NOTHROW if inside a noexcept?
> 
> That doesn't sound worthwhile to me.
> 
>> +/* Parse a conditional-expression.  */
>> +/* FIXME: should callers use cp_parser_constant_expression?  */
> 
> It doesn't really matter since C++11 generalized constant expressions; 
> we don't need to enforce their rules in the parser anymore.
> 
>> +/* Return the source text between two locations.  */
>> +
>> +static char *
>> +get_source (location_t start, location_t end)
> 
> This seems like it belongs in libcpp.  It also needs to
> 
>> +  /* FIXME how should we handle newlines and runs of spaces?  */
>> +  char buf[1024 + 4]{};
>> +  char *res = buf;
>> +  size_t len = 1024;
> 
> Obstacks work very well for temporary buffers like this.
> 
>> +/* Pretty print an expression and return the result as a char*.  */
>> +
>> +static char*
>> +stringify_tree (tree expr)
> 
> Is there a reason not to use expr_to_string?
> 
>> +  /* TODO: If this is a postcondition and the return type is deduced,
>> +     then we need to cache tokens and parse when the function is
>> +     defined.
> 
> Yes.
> 
>> +     Would it be okay to declare the result decl as having a deduced
>> +     return type also?
> 
> For a template, yes.  For a non-templated function, no.
> 
>> +     NOTE: You can't declare a deduced return type function with
>> +     postconditions and not define it.  */
> 
> Well, you can, but you can't call it, so it doesn't matter if we haven't 
> figured out the contracts.
> 
>> +   FIXME: There are probably earlier exits than end of file. What
>> +   about a semicolon?  */
> 
> You could use cp_parser_skip_to_closing_parenthesis_1 to look for an 
> un-nested ] and then complain if it isn't followed by another ].
> 
>> +/* 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. */
> 
> You will want to use forward_parm in this function.
> 
>> +      if (VOID_TYPE_P (t))
>> +       continue;
> 
> There are no void parameters in DECL_ARGUMENTS (only in TYPE_ARG_TYPES).
> 
>> +      error ("guarded function %q+D overriding non-guarded function",
> 
> The term "guarded" doesn't seem to appear in any of the contracts papers 
> other than yours, so let's word this differently.
> 
>> +      error ("guarded function %q+D overriding non-guarded function",
>> +            overrider);
>> +      inform (DECL_SOURCE_LOCATION (basefn),
>> +             "overridden function is %qD", basefn);
>> +      return 0; // FIXME?
> 
> What's to fix?
> 
>> +  /* FIXME: Why do we have two unrelated statement lists?  */
>> +  tree def = push_stmt_list();
>> +  tree body = begin_compound_stmt (BCS_NORMAL);
> 
> You probably want begin_function_body instead of push_stmt_list.
> 
>> +  finish_function_body (TREE_VALUE (def));
> 
> And then a finish_compound_stmt before the finish_function_body.
> 
>> +  /* FIXME we're marking the unchecked fn decl as not virtual, so why 
>> do we
>> +     need to disallow virtual when building the call? */
> 
> Indeed, the disallow_virtual argument only matters for virtual 
> functions, so either value is fine.
> 
>> +  /* FIXME it may make more sense to have the checked function be 
>> concrete
>> +     with the unchecked be virtual since all checked function 
>> overrides must
>> +     be equivalent due to the contract matching requirement.  */
> 
> Doing it that way would allow better inlining of the checking wrapper, 
> but would require some way to specify virtual or non-virtual calling 
> from the checking wrapper to the unchecked function.
> 
>> +  /* FIXME temporarily inlined from finish_compound_stmt except for 
>> actually
>> +     adding the compound statement to the current statement list. We 
>> need
>> +     several parts of this logic to handle normal and template 
>> parsing for
>> +     postconditions, but is there something better we can use 
>> instead?  */
> 
> You could push/pop_stmt_list around the call to finish_compound_stmt to 
> capture the result.
> 
>> +  tree level_str = build_string_literal (strlen (level) + 1, level);
>> +  tree role_str = build_string_literal (strlen (role) + 1, role);
> 
> Maybe combine these into a single string argument?
> 
>> +  /* We never want to accidentally instantiate templates.  */
>> +  if (code == TEMPLATE_DECL)
>> +    return *tp; /* FIXME? */
> 
> This seems unlikely to have the desired effect; we should see template 
> instantiations as FUNCTION_DECL or VAR_DECL.  I'm also not sure what the 
> cp_tree_defined_p check is trying to do; surely using defined functions 
> and variables can also lead to runtime code?
> 
>> +  /* FIXME: This code gen will be moved to gimple.  */
> 
> It should be simple enough to move to cp_genericize_r.
> 
>> +  /* The condition is converted to bool.
>> +
>> +     FIXME: When we instantiate this, the input location is in entirely
>> +     the wrong place.  */
> 
> It should work to attach the location to the contract _STMT.
> 
>> @@ -14156,6 +14156,7 @@ gimplify_expr (tree *expr_p, gimple_seq 
>> *pre_p, gimple_seq *post_p,
>>               goto dont_recalculate;
>>
>>             default:
>> +              debug_tree (*expr_p);
> 
> Leftover debugging code.
> 
>> +      /* If we don't have contracts and haven't already set the deferred
>> +        contracts to a "no initial contracts" sentinel, do so now to 
>> support
>> +        flag_contract_strict_declarations.  */
> 
> What is the advantage of this sentinel over NULL_TREE?
> 
>> +// TODO FIXME override stops parsing of attrs silently?
> 
> Any more information about this?
> 
>> +    /* FIXME: should the contracts on a friend decl be a complete class
>> +       context for the type being currently defined? */
>> +  /* FIXME contracts can be parsed inside of a class when the decl is 
>> a friend? */
> 
> I would expect all contract attributes in a class to be complete class 
> contexts, whether the function is a member or friend.
> 
>> +  /* FIXME Is this right for friends? Can a friend refer to a static 
>> member?
>> +     Can a friend's contracts refer to our privates? Turning them into
>> +     [[assert]]s inside the body of the friend itself certainly lets 
>> them do
>> +     so. */
> 
> P0542 says contracts are limited to the accessibility of the function 
> itself, so a friend cannot refer to private members.
> 
>> +  /* FIXME Do instantiations mean anything in the context of 
>> contracts?  */
> 
> No; I'm not sure what they mean for default arguments.

Now I understand again what they mean for default arguments: if we need 
to instantiate a member function before its default arguments have been 
parsed, we stick the same DEFERRED_PARSE in the default arguments of the 
instantiation, and then replace any of those with the parsed result once 
we have it.  Since you wait to substitute contracts until you are 
instantiating the function definition, you shouldn't need anything like 
that.

>> +      DECL_DEFERRED_CONTRACTS (decl) = chainon (
>> +         DECL_DEFERRED_CONTRACTS (decl),
>> +         build_tree_list (original_loc, fn->contracts));
> 
> This indentation pattern occurs pretty often in the patch, but doesn't 
> match the usual style in GCC sources; there's only one occurrence of a 
> left paren at the end of a line.  Please move it to the beginning of the 
> argument list on the next line.  The following lines also seem more 
> indented than necessary.
> 
> Jason

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2019-12-10  5:58 ` Jason Merrill
  2019-12-10  6:20   ` Jason Merrill
@ 2020-03-24 14:23   ` Andrew Sutton
  2020-05-07 15:56   ` Jeff Chapman
  2 siblings, 0 replies; 31+ messages in thread
From: Andrew Sutton @ 2020-03-24 14:23 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Chapman, gcc-patches

Hi Jason,

Sorry I haven't been able to get back to this. I've been swamped with
other work, and we haven't had the resources to properly address this.
Jeff Chapman will be working on cleaning this up for when master/trunk
re-opens.


> I find the proposed always_continue semantics kind of nonsensical, as
> somewhat evidenced by the contortions the implementation gets into with
> marking the violation handler as pure.  The trick of assigning the
> result to a local variable won't work with optimization.

We tend to agree and think it's practically non-implementable. IIRC,
later contracts proposals steered away from adding this as a concrete
semantic. I suspect killing this would be fine.

> > +/* Definitions for C++ contract levels
> > +   Copyright (C) 1987-2018 Free Software Foundation, Inc.
>
> Should just be 2019 for a new file.

Probably 2020 now :)

> > +   Contributed by Michael Tiemann (tiemann@cygnus.com)
>
> This seems inaccurate.  :)

Indeed :)


> This change to member function redeclaration seems undesirable; your
> rationale in P1680 is "for generality", but member functions are already
> stricter about redeclaration than non-member functions; I don't see a
> reason to relax this rule just for contracts.  With member functions,
> there *is* always a canonical first declaration, and people expect the
> class definition to have its complete interface, of which contracts are
> a part.

There was a proposal that gave more motivation than just "for
generality". Apparently, I was a co-author -- I think I just helped
write the wording.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1320r2.html


> For non-member functions, we still need to complain if contracts are
> added after we've seen an ODR-use of the function, just like with
> explicit specializations.

We could do that, but it doesn't seem necessary with this model.
Whether the contracts have been seen or not doesn't affect which
function is called.


> > +      /* TODO is there any way to relax this requirement?  */
> > +      if (DECL_VIRTUAL_P (olddecl) && !TYPE_BEING_DEFINED (DECL_CONTEXT (olddecl)))
>
> Relatedly, I don't think we want to relax this requirement.

Probably. Virtual functions and contracts have complex interactions.
There are going to be more EWG papers about this, I'm sure.


> > +  /* FIXME Is this right for friends? Can a friend refer to a static member?
> > +     Can a friend's contracts refer to our privates? Turning them into
> > +     [[assert]]s inside the body of the friend itself certainly lets them do
> > +     so. */
>
> P0542 says contracts are limited to the accessibility of the function
> itself, so a friend cannot refer to private members.

That will almost certainly be changed. This was the proposal:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1289r0.pdf

There was near-unanimous support for removing that (19 for, 1 against).

Andrew

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2019-12-10  5:58 ` Jason Merrill
  2019-12-10  6:20   ` Jason Merrill
  2020-03-24 14:23   ` Andrew Sutton
@ 2020-05-07 15:56   ` Jeff Chapman
  2020-07-10 17:53     ` Jeff Chapman
  2 siblings, 1 reply; 31+ messages in thread
From: Jeff Chapman @ 2020-05-07 15:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Andrew Sutton

[-- Attachment #1: Type: text/plain, Size: 5899 bytes --]

Hello,

On 12/10/19, Jason Merrill wrote:
> On 11/13/19, Jeff Chapman wrote:
>> Attached is a patch that implements pre-c++20 contracts. This comes
>> from a long running development branch which included ChangeLog entries
>> as we went, which are included in the patch itself. The repo and
>> initial wiki are located here:
>> https://gitlab.com/lock3/gcc-new/wikis/GCC-with-Contracts
>
> Thanks.  I've mostly been referring to the repo rather than the attached
> patch.  Below are a bunch of comments about the implementation, in no
> particular order.
>

I've attached a new squashed revision of the patch, and you can see the
changes I've made from your input on the contracts-jac-prep branch:
https://gitlab.com/lock3/gcc-new/-/tree/contracts-jac-prep . If there's
an easier format for you to review that I can produce please let me
know.

I'll address a few things inline below. Everything else should either be
handled or explained by Andrew's last email. If anything needs further
addressing or something hasn't been brought up yet please let me know :)


>> +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");
>
> Hmm, P1429 includes the notion of build level, it's just checked after
> explicit semantics.  In general, P1429 seems like a compatible extension
> of the semantics previously in the working paper.
>
> P1332 could also be treated as compatible if we consider the P0542 build
> level to affect the default role as specified in P1429.  P1680 seems to
> suggest that this is what you had in mind.
>

These could possibly be made compatible, but in some cases the flags are
changing the same entries in the table. That would require deciding
whether flag ordering matters or whether a certain flags can't change
values set by other flags.

I'm not sure it's a worthwhile change. While it increases the valid
space of command line invocations, it doesn't actually increase the the
result space. I'd prefer an eventual solution that removed flags
entirely instead.


>> +  /* Check that assertions are null statements.  */
>> +  if (attribute_contract_assert_p (contract_attrs))
>> +    if (token->type != CPP_SEMICOLON)
>> +      error_at (token->location, "assertions must be followed by
>> %<;%>");
>
> Better I think to handle this further down where [[fallthrough]] has the
> same requirement.
>

I'm wondering if it would be better to move [[fallthrough]] up, since
the later check is not always executed and in the case of [[assert]] we
actually need to error.

  [[fallthrough]] int x;

for instance just gets a generic 'attribute ignored' warning. I'm not
entirely happy with how we prevent assert/pre/post from appearing in
invalid locations in general which I'll try to improve. If you have
concrete suggestions please let me know.


> Why not leave the function the user declared as the unchecked function
> (just changing some linkage properties) and create a new function for
> the checked wrapper?
>

This revision of the patch does not include changes to the
checked/unchecked function split. We're exploring an alternative rewrite
that leaves the original function declaration alone and should address
or sidestep a number of these comments.

Specifically, we're exploring generating pre and post functions with
calls to them in the correct places (upon entering a guarded function,
wrapping the return value):

  int f(int n) [[ pre: n > 0 ]] [[ post r: r < 0 ]] { return -n; }

turns into

  void __pre_f(int n) { [[ assert: n > 0 ]]; }
  int __post_f(int r) { [[ assert: r < 0 ]]; return r; }
  int f(int n) {
    __pre_f(n);
    return __post_f(-n);
  }

with whatever hints we can give to optimize this as much as possible.


>> +/* Return the source text between two locations.  */
>> +
>> +static char *
>> +get_source (location_t start, location_t end)
>
> This seems like it belongs in libcpp.  It also needs to
>

This has been moved to input since it uses input functions, but needs
more work. Was there another comment you had that cutoff?


>> +  tree level_str = build_string_literal (strlen (level) + 1, level);
>> +  tree role_str = build_string_literal (strlen (role) + 1, role);
>
> Maybe combine these into a single string argument?
>

These are used separately in std::contract_violation and to my
understanding building them separately will collapse duplicate levels
and roles instead of duplicating them unless they both match -- is that
correct?


>> +  /* We never want to accidentally instantiate templates.  */
>> +  if (code == TEMPLATE_DECL)
>> +    return *tp; /* FIXME? */
>
> This seems unlikely to have the desired effect; we should see template
> instantiations as FUNCTION_DECL or VAR_DECL.  I'm also not sure what the
> cp_tree_defined_p check is trying to do; surely using defined functions
> and variables can also lead to runtime code?
>

This is an result of the transform we do for axioms when they're enabled
that you may know of a better way to do. Essentially we turn this:

  [[ assert axiom: f() > 0 ]];

into this:

  if (!(f() > 0))
    __builtin_unreachable ();

but we potentially run into issues later if f isn't (yet) defined or is
defined in a different translation unit, such as constexpr time. We're
avoiding those errors by generating a nop if there's any chance can't be
evaluated. We'd prefer something like

  __builtin_assume (f() > 0);

where the condition is simply ignored if enough information isn't
present to affect codegen. Is there a better way to handle this?

I should mention that there are likely significant further changes
around axiom coming down the pike that may tie into or replace the
"is defined" check. Specifically for expressions that _cannot_ be
defined rather than ones that are simply not yet defined.

[-- Attachment #2: 0001-Implement-pre-c-20-contracts.patch.gz --]
[-- Type: application/x-gzip, Size: 102273 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2020-05-07 15:56   ` Jeff Chapman
@ 2020-07-10 17:53     ` Jeff Chapman
  2020-07-28 12:52       ` Jeff Chapman
  2020-12-02 20:33       ` Jason Merrill
  0 siblings, 2 replies; 31+ messages in thread
From: Jeff Chapman @ 2020-07-10 17:53 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Andrew Sutton

[-- Attachment #1: Type: text/plain, Size: 4486 bytes --]

Hello again :)

Attached is a new squashed revision of the patch sans ChangeLogs. The
current work is now being done on github:
https://github.com/lock3/gcc/tree/contracts-jac-alt

Please let me know if there's a better way to share revisions.

>>> +  /* Check that assertions are null statements.  */
>>> +  if (attribute_contract_assert_p (contract_attrs))
>>> +    if (token->type != CPP_SEMICOLON)
>>> +      error_at (token->location, "assertions must be followed by
>>> %<;%>");
>>
>> Better I think to handle this further down where [[fallthrough]] has the
>> same requirement.
>>
>
> I'm wondering if it would be better to move [[fallthrough]] up, since
> the later check is not always executed and in the case of [[assert]] we
> actually need to error.
>
>   [[fallthrough]] int x;
>
> for instance just gets a generic 'attribute ignored' warning. I'm not
> entirely happy with how we prevent assert/pre/post from appearing in
> invalid locations in general which I'll try to improve. If you have
> concrete suggestions please let me know.

Improvements have been made to handling contract attributes appearing in
places they don't belong. Any feedback about moving the logic dealing
with [[fallthrough]]?


>> Why not leave the function the user declared as the unchecked function
>> (just changing some linkage properties) and create a new function for
>> the checked wrapper?
>>
>
> This revision of the patch does not include changes to the
> checked/unchecked function split. We're exploring an alternative rewrite
> that leaves the original function declaration alone and should address
> or sidestep a number of these comments.
>
> Specifically, we're exploring generating pre and post functions with
> calls to them in the correct places (upon entering a guarded function,
> wrapping the return value):
>
>   int f(int n) [[ pre: n > 0 ]] [[ post r: r < 0 ]] { return -n; }
>
> turns into
>
>   void __pre_f(int n) { [[ assert: n > 0 ]]; }
>   int __post_f(int r) { [[ assert: r < 0 ]]; return r; }
>   int f(int n) {
>     __pre_f(n);
>     return __post_f(-n);
>   }
>
> with whatever hints we can give to optimize this as much as possible.

This is the main change since the last submission. We now leave the
original decl intact and instead generate a pre and post function.
Naming and mangling of these pre/post functions needs addressed.

Beyond that, more cleanup has been done. There's still outstanding
cleanup work, mostly around investigating and improving performance.
Feedback on the main direction of the patch would be appreciated, and
any specific commentary or directions of investigation would be helpful.


>>> +/* Return the source text between two locations.  */
>>> +
>>> +static char *
>>> +get_source (location_t start, location_t end)
>>
>> This seems like it belongs in libcpp.  It also needs to
>>
>
> This has been moved to input since it uses input functions, but needs
> more work. Was there another comment you had that cutoff?
>
> ...snip...
>
>>> +  /* We never want to accidentally instantiate templates.  */
>>> +  if (code == TEMPLATE_DECL)
>>> +    return *tp; /* FIXME? */
>>
>> This seems unlikely to have the desired effect; we should see template
>> instantiations as FUNCTION_DECL or VAR_DECL.  I'm also not sure what the
>> cp_tree_defined_p check is trying to do; surely using defined functions
>> and variables can also lead to runtime code?
>>
>
> This is an result of the transform we do for axioms when they're enabled
> that you may know of a better way to do. Essentially we turn this:
>
>   [[ assert axiom: f() > 0 ]];
>
> into this:
>
>   if (!(f() > 0))
>     __builtin_unreachable ();
>
> but we potentially run into issues later if f isn't (yet) defined or is
> defined in a different translation unit, such as constexpr time. We're
> avoiding those errors by generating a nop if there's any chance can't be
> evaluated. We'd prefer something like
>
>   __builtin_assume (f() > 0);
>
> where the condition is simply ignored if enough information isn't
> present to affect codegen. Is there a better way to handle this?
>
> I should mention that there are likely significant further changes
> around axiom coming down the pike that may tie into or replace the
> "is defined" check. Specifically for expressions that _cannot_ be
> defined rather than ones that are simply not yet defined.
>

Not much has changed yet regarding axiom, but if you have any
suggestions for handling any of the above then I'm all ears.

[-- Attachment #2: 0001-Implement-pre-c-20-contracts.patch.gz --]
[-- Type: application/x-gzip, Size: 75262 bytes --]

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2020-07-10 17:53     ` Jeff Chapman
@ 2020-07-28 12:52       ` Jeff Chapman
  2020-12-02 20:33       ` Jason Merrill
  1 sibling, 0 replies; 31+ messages in thread
From: Jeff Chapman @ 2020-07-28 12:52 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches; +Cc: Andrew Sutton

Ping. Any feedback would be appreciated :)

re: https://gcc.gnu.org/pipermail/gcc-patches/2020-July/549868.html
older reply: https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545339.html

On 7/10/20, Jeff Chapman <jchapman@lock3software.com> wrote:
> Hello again :)
>
> Attached is a new squashed revision of the patch sans ChangeLogs. The
> current work is now being done on github:
> https://github.com/lock3/gcc/tree/contracts-jac-alt
>
> Please let me know if there's a better way to share revisions.
>
>>>> +  /* Check that assertions are null statements.  */
>>>> +  if (attribute_contract_assert_p (contract_attrs))
>>>> +    if (token->type != CPP_SEMICOLON)
>>>> +      error_at (token->location, "assertions must be followed by
>>>> %<;%>");
>>>
>>> Better I think to handle this further down where [[fallthrough]] has the
>>> same requirement.
>>>
>>
>> I'm wondering if it would be better to move [[fallthrough]] up, since
>> the later check is not always executed and in the case of [[assert]] we
>> actually need to error.
>>
>>   [[fallthrough]] int x;
>>
>> for instance just gets a generic 'attribute ignored' warning. I'm not
>> entirely happy with how we prevent assert/pre/post from appearing in
>> invalid locations in general which I'll try to improve. If you have
>> concrete suggestions please let me know.
>
> Improvements have been made to handling contract attributes appearing in
> places they don't belong. Any feedback about moving the logic dealing
> with [[fallthrough]]?
>
>
>>> Why not leave the function the user declared as the unchecked function
>>> (just changing some linkage properties) and create a new function for
>>> the checked wrapper?
>>>
>>
>> This revision of the patch does not include changes to the
>> checked/unchecked function split. We're exploring an alternative rewrite
>> that leaves the original function declaration alone and should address
>> or sidestep a number of these comments.
>>
>> Specifically, we're exploring generating pre and post functions with
>> calls to them in the correct places (upon entering a guarded function,
>> wrapping the return value):
>>
>>   int f(int n) [[ pre: n > 0 ]] [[ post r: r < 0 ]] { return -n; }
>>
>> turns into
>>
>>   void __pre_f(int n) { [[ assert: n > 0 ]]; }
>>   int __post_f(int r) { [[ assert: r < 0 ]]; return r; }
>>   int f(int n) {
>>     __pre_f(n);
>>     return __post_f(-n);
>>   }
>>
>> with whatever hints we can give to optimize this as much as possible.
>
> This is the main change since the last submission. We now leave the
> original decl intact and instead generate a pre and post function.
> Naming and mangling of these pre/post functions needs addressed.
>
> Beyond that, more cleanup has been done. There's still outstanding
> cleanup work, mostly around investigating and improving performance.
> Feedback on the main direction of the patch would be appreciated, and
> any specific commentary or directions of investigation would be helpful.
>
>
>>>> +/* Return the source text between two locations.  */
>>>> +
>>>> +static char *
>>>> +get_source (location_t start, location_t end)
>>>
>>> This seems like it belongs in libcpp.  It also needs to
>>>
>>
>> This has been moved to input since it uses input functions, but needs
>> more work. Was there another comment you had that cutoff?
>>
>> ...snip...
>>
>>>> +  /* We never want to accidentally instantiate templates.  */
>>>> +  if (code == TEMPLATE_DECL)
>>>> +    return *tp; /* FIXME? */
>>>
>>> This seems unlikely to have the desired effect; we should see template
>>> instantiations as FUNCTION_DECL or VAR_DECL.  I'm also not sure what the
>>> cp_tree_defined_p check is trying to do; surely using defined functions
>>> and variables can also lead to runtime code?
>>>
>>
>> This is an result of the transform we do for axioms when they're enabled
>> that you may know of a better way to do. Essentially we turn this:
>>
>>   [[ assert axiom: f() > 0 ]];
>>
>> into this:
>>
>>   if (!(f() > 0))
>>     __builtin_unreachable ();
>>
>> but we potentially run into issues later if f isn't (yet) defined or is
>> defined in a different translation unit, such as constexpr time. We're
>> avoiding those errors by generating a nop if there's any chance can't be
>> evaluated. We'd prefer something like
>>
>>   __builtin_assume (f() > 0);
>>
>> where the condition is simply ignored if enough information isn't
>> present to affect codegen. Is there a better way to handle this?
>>
>> I should mention that there are likely significant further changes
>> around axiom coming down the pike that may tie into or replace the
>> "is defined" check. Specifically for expressions that _cannot_ be
>> defined rather than ones that are simply not yet defined.
>>
>
> Not much has changed yet regarding axiom, but if you have any
> suggestions for handling any of the above then I'm all ears.
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2020-07-10 17:53     ` Jeff Chapman
  2020-07-28 12:52       ` Jeff Chapman
@ 2020-12-02 20:33       ` Jason Merrill
  2020-12-03 17:07         ` Andrew Sutton
  1 sibling, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2020-12-02 20:33 UTC (permalink / raw)
  To: Jeff Chapman; +Cc: gcc-patches, Andrew Sutton

On 7/10/20 1:53 PM, Jeff Chapman wrote:
> Hello again :)
> 
> Attached is a new squashed revision of the patch sans ChangeLogs. The
> current work is now being done on github:
> https://github.com/lock3/gcc/tree/contracts-jac-alt

I'm starting to review this now, sorry for the delay. Is this still the 
branch you want me to consider for GCC 11?  I notice that the -constexpr 
and -mangled-config branches are newer.

> 
> Please let me know if there's a better way to share revisions.
> 
>>>> +  /* Check that assertions are null statements.  */
>>>> +  if (attribute_contract_assert_p (contract_attrs))
>>>> +    if (token->type != CPP_SEMICOLON)
>>>> +      error_at (token->location, "assertions must be followed by
>>>> %<;%>");
>>>
>>> Better I think to handle this further down where [[fallthrough]] has the
>>> same requirement.
>>>
>>
>> I'm wondering if it would be better to move [[fallthrough]] up, since
>> the later check is not always executed and in the case of [[assert]] we
>> actually need to error.
>>
>>    [[fallthrough]] int x;
>>
>> for instance just gets a generic 'attribute ignored' warning. I'm not
>> entirely happy with how we prevent assert/pre/post from appearing in
>> invalid locations in general which I'll try to improve. If you have
>> concrete suggestions please let me know.
> 
> Improvements have been made to handling contract attributes appearing in
> places they don't belong. Any feedback about moving the logic dealing
> with [[fallthrough]]?
> 
> 
>>> Why not leave the function the user declared as the unchecked function
>>> (just changing some linkage properties) and create a new function for
>>> the checked wrapper?
>>>
>>
>> This revision of the patch does not include changes to the
>> checked/unchecked function split. We're exploring an alternative rewrite
>> that leaves the original function declaration alone and should address
>> or sidestep a number of these comments.
>>
>> Specifically, we're exploring generating pre and post functions with
>> calls to them in the correct places (upon entering a guarded function,
>> wrapping the return value):
>>
>>    int f(int n) [[ pre: n > 0 ]] [[ post r: r < 0 ]] { return -n; }
>>
>> turns into
>>
>>    void __pre_f(int n) { [[ assert: n > 0 ]]; }
>>    int __post_f(int r) { [[ assert: r < 0 ]]; return r; }
>>    int f(int n) {
>>      __pre_f(n);
>>      return __post_f(-n);
>>    }
>>
>> with whatever hints we can give to optimize this as much as possible.
> 
> This is the main change since the last submission. We now leave the
> original decl intact and instead generate a pre and post function.
> Naming and mangling of these pre/post functions needs addressed.
> 
> Beyond that, more cleanup has been done. There's still outstanding
> cleanup work, mostly around investigating and improving performance.
> Feedback on the main direction of the patch would be appreciated, and
> any specific commentary or directions of investigation would be helpful.
> 
> 
>>>> +/* Return the source text between two locations.  */
>>>> +
>>>> +static char *
>>>> +get_source (location_t start, location_t end)
>>>
>>> This seems like it belongs in libcpp.  It also needs to
>>>
>>
>> This has been moved to input since it uses input functions, but needs
>> more work. Was there another comment you had that cutoff?
>>
>> ...snip...
>>
>>>> +  /* We never want to accidentally instantiate templates.  */
>>>> +  if (code == TEMPLATE_DECL)
>>>> +    return *tp; /* FIXME? */
>>>
>>> This seems unlikely to have the desired effect; we should see template
>>> instantiations as FUNCTION_DECL or VAR_DECL.  I'm also not sure what the
>>> cp_tree_defined_p check is trying to do; surely using defined functions
>>> and variables can also lead to runtime code?
>>>
>>
>> This is an result of the transform we do for axioms when they're enabled
>> that you may know of a better way to do. Essentially we turn this:
>>
>>    [[ assert axiom: f() > 0 ]];
>>
>> into this:
>>
>>    if (!(f() > 0))
>>      __builtin_unreachable ();
>>
>> but we potentially run into issues later if f isn't (yet) defined or is
>> defined in a different translation unit, such as constexpr time. We're
>> avoiding those errors by generating a nop if there's any chance can't be
>> evaluated. We'd prefer something like
>>
>>    __builtin_assume (f() > 0);
>>
>> where the condition is simply ignored if enough information isn't
>> present to affect codegen. Is there a better way to handle this?
>>
>> I should mention that there are likely significant further changes
>> around axiom coming down the pike that may tie into or replace the
>> "is defined" check. Specifically for expressions that _cannot_ be
>> defined rather than ones that are simply not yet defined.
>>
> 
> Not much has changed yet regarding axiom, but if you have any
> suggestions for handling any of the above then I'm all ears.
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2020-12-02 20:33       ` Jason Merrill
@ 2020-12-03 17:07         ` Andrew Sutton
  2020-12-03 17:41           ` Jason Merrill
  0 siblings, 1 reply; 31+ messages in thread
From: Andrew Sutton @ 2020-12-03 17:07 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Chapman, gcc-patches

>
>
> > Attached is a new squashed revision of the patch sans ChangeLogs. The
> > current work is now being done on github:
> > https://github.com/lock3/gcc/tree/contracts-jac-alt
>
> I'm starting to review this now, sorry for the delay. Is this still the
> branch you want me to consider for GCC 11?  I notice that the -constexpr
> and -mangled-config branches are newer.


I think so. Jeff can answer more authoritatively. I know we had one set of
changes to the design (how contracts) work aimed at improving the debugging
experience for violated contracts. I'm not sure if that's in the jac-alt
branch though.

The -constexpr branch checks for trivially satisfied contracts (e.g.,
[[assert: true]]) and issues warnings. It also preemptively checks
preconditions against constant function arguments. It's probably worth
reviewing that separately.

I'm not sure the -manged-config branch is worth considering for merging at
this point. It's trying to solve a problem that might not be worth solving.

Out of curiosity, are you concerned that future versions of contracts might
have considerably different syntax or configurability? I'd hope it
wouldn't, but who knows where SG21 is going :)

Andrew

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2020-12-03 17:07         ` Andrew Sutton
@ 2020-12-03 17:41           ` Jason Merrill
  2020-12-04 13:35             ` Jeff Chapman
  0 siblings, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2020-12-03 17:41 UTC (permalink / raw)
  To: Andrew Sutton; +Cc: Jeff Chapman, gcc-patches

On 12/3/20 12:07 PM, Andrew Sutton wrote:
> 
>      > Attached is a new squashed revision of the patch sans ChangeLogs. The
>      > current work is now being done on github:
>      > https://github.com/lock3/gcc/tree/contracts-jac-alt
>     <https://github.com/lock3/gcc/tree/contracts-jac-alt>
> 
>     I'm starting to review this now, sorry for the delay. Is this still the
>     branch you want me to consider for GCC 11?  I notice that the
>     -constexpr
>     and -mangled-config branches are newer.
> 
> 
> I think so. Jeff can answer more authoritatively. I know we had one set 
> of changes to the design (how contracts) work aimed at improving the 
> debugging experience for violated contracts. I'm not sure if that's in 
> the jac-alt branch though.
> 
> The -constexpr branch checks for trivially satisfied contracts (e.g., 
> [[assert: true]]) and issues warnings. It also preemptively checks 
> preconditions against constant function arguments. It's probably worth 
> reviewing that separately.
> 
> I'm not sure the -manged-config branch is worth considering for merging 
> at this point. It's trying to solve a problem that might not be worth 
> solving.

OK, I'll start with -alt then, thanks.

> Out of curiosity, are you concerned that future versions of contracts 
> might have considerably different syntax or configurability? I'd hope it 
> wouldn't, but who knows where SG21 is going :)

Not particularly; I figure that most of the implementation would be 
unaffected.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] implement pre-c++20 contracts
  2020-12-03 17:41           ` Jason Merrill
@ 2020-12-04 13:35             ` Jeff Chapman
  2021-01-04 14:58               ` [PATCH] PING " Jeff Chapman
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Chapman @ 2020-12-04 13:35 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Andrew Sutton, gcc-patches

> OK, I'll start with -alt then, thanks.

Andrew is exactly correct, contracts-jac-alt is still the current branch
we're focusing our upstreaming efforts on.

It's trailing upstream master by a fair bit at this point. I'll get a merge
pushed shortly.

Please let me know if there's anything I can do to help review along!


On Thu, Dec 3, 2020 at 12:41 PM Jason Merrill <jason@redhat.com> wrote:

> On 12/3/20 12:07 PM, Andrew Sutton wrote:
> >
> >      > Attached is a new squashed revision of the patch sans ChangeLogs.
> The
> >      > current work is now being done on github:
> >      > https://github.com/lock3/gcc/tree/contracts-jac-alt
> >     <https://github.com/lock3/gcc/tree/contracts-jac-alt>
> >
> >     I'm starting to review this now, sorry for the delay. Is this still
> the
> >     branch you want me to consider for GCC 11?  I notice that the
> >     -constexpr
> >     and -mangled-config branches are newer.
> >
> >
> > I think so. Jeff can answer more authoritatively. I know we had one set
> > of changes to the design (how contracts) work aimed at improving the
> > debugging experience for violated contracts. I'm not sure if that's in
> > the jac-alt branch though.
> >
> > The -constexpr branch checks for trivially satisfied contracts (e.g.,
> > [[assert: true]]) and issues warnings. It also preemptively checks
> > preconditions against constant function arguments. It's probably worth
> > reviewing that separately.
> >
> > I'm not sure the -manged-config branch is worth considering for merging
> > at this point. It's trying to solve a problem that might not be worth
> > solving.
>
> OK, I'll start with -alt then, thanks.
>
> > Out of curiosity, are you concerned that future versions of contracts
> > might have considerably different syntax or configurability? I'd hope it
> > wouldn't, but who knows where SG21 is going :)
>
> Not particularly; I figure that most of the implementation would be
> unaffected.
>
> Jason
>
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] PING implement pre-c++20 contracts
  2020-12-04 13:35             ` Jeff Chapman
@ 2021-01-04 14:58               ` Jeff Chapman
  2021-01-05 21:27                 ` Jason Merrill
  2021-01-18 14:56                 ` Jason Merrill
  0 siblings, 2 replies; 31+ messages in thread
From: Jeff Chapman @ 2021-01-04 14:58 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Andrew Sutton, gcc-patches

Ping. re:
https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html

> OK, I'll start with -alt then, thanks.
>
> Andrew is exactly correct, contracts-jac-alt is still the current branch
> we're focusing our upstreaming efforts on.
>
> It's trailing upstream master by a fair bit at this point. I'll get a
> merge pushed shortly.
>

The latest is still on the same branch, which hasn't been updated since
that last merge:
https://github.com/lock3/gcc/tree/contracts-jac-alt

Would you prefer me to keep it from trailing upstream too much through
regular merges, or would it be more beneficial for it to be left alone so
you have a more stable review target?

Please let me know if there's initial feedback I can start addressing, or
anything I can do to help the review process along in general.

Thank you,
Jeff Chapman

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-01-04 14:58               ` [PATCH] PING " Jeff Chapman
@ 2021-01-05 21:27                 ` Jason Merrill
  2021-01-18 14:56                 ` Jason Merrill
  1 sibling, 0 replies; 31+ messages in thread
From: Jason Merrill @ 2021-01-05 21:27 UTC (permalink / raw)
  To: Jeff Chapman; +Cc: Andrew Sutton, gcc-patches

On 1/4/21 9:58 AM, Jeff Chapman wrote:
> Ping. re: 
> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html 
> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
> 
>      > OK, I'll start with -alt then, thanks.
> 
>     Andrew is exactly correct, contracts-jac-alt is still the current
>     branch we're focusing our upstreaming efforts on.
> 
>     It's trailing upstream master by a fair bit at this point. I'll get
>     a merge pushed shortly.
> 
> 
> The latest is still on the same branch, which hasn't been updated since 
> that last merge:
> https://github.com/lock3/gcc/tree/contracts-jac-alt 
> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
> 
> Would you prefer me to keep it from trailing upstream too much through 
> regular merges, or would it be more beneficial for it to be left alone 
> so you have a more stable review target?

Either way I'm reviewing by diff against the most recent merged trunk 
revision, so it doesn't really matter.

But you probably want to do one merge at least, to make sure that 
modules and contracts coexist well.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-01-04 14:58               ` [PATCH] PING " Jeff Chapman
  2021-01-05 21:27                 ` Jason Merrill
@ 2021-01-18 14:56                 ` Jason Merrill
  2021-03-01 13:12                   ` Jeff Chapman
  1 sibling, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2021-01-18 14:56 UTC (permalink / raw)
  To: Jeff Chapman; +Cc: Andrew Sutton, gcc-patches

On 1/4/21 9:58 AM, Jeff Chapman wrote:
> Ping. re: 
> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html 
> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
> 
>      > OK, I'll start with -alt then, thanks.
> 
>     Andrew is exactly correct, contracts-jac-alt is still the current
>     branch we're focusing our upstreaming efforts on.
> 
>     It's trailing upstream master by a fair bit at this point. I'll get
>     a merge pushed shortly.
> 
> 
> The latest is still on the same branch, which hasn't been updated since 
> that last merge:
> https://github.com/lock3/gcc/tree/contracts-jac-alt 
> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
> 
> Would you prefer me to keep it from trailing upstream too much through 
> regular merges, or would it be more beneficial for it to be left alone 
> so you have a more stable review target?
> 
> Please let me know if there's initial feedback I can start addressing, 
> or anything I can do to help the review process along in general.

Why is some of the code in c-family?  From the modules merge there is 
now a cp_handle_option function that you could add the option handling 
to, and I don't see a reason for cxx-contracts.c to be in c-family/ 
rather than cp/.

And then much of the code you add to decl.c could also move to the 
contracts file, and some of the contracts stuff in cp-tree.h could move 
to cxx-contracts.h?

> +extern bool cxx23_contract_attribute_p (const_tree);

This name seems optimistic.  :)
Let's call it cxx_contract_attribute_p.

> +/* Return TRUE iff ATTR has been parsed by the fornt-end as a c++2a contract

"front"

> @@ -566,7 +566,11 @@ decl_attributes (tree *node, tree attributes, int flags,
>         {
>           if (!(flags & (int) ATTR_FLAG_BUILT_IN))
>             {
> -             if (ns == NULL_TREE || !cxx11_attr_p)
> +             if (cxx23_contract_attribute_p (attr))
> +               {
> +                 ; /* Do not warn about contract "attributes".  */
> +               }

I don't want the language-independent code to have to know about this. 
If you want decl_attributes to ignore these attributes, you could give 
these attributes a dummy spec that just returns?

> +set_decl_contracts (tree decl, tree contract_attrs)
> +{
> +  remove_contract_attributes (decl);
> +  if (!DECL_ATTRIBUTES (decl))
> +    {
> +      DECL_ATTRIBUTES (decl) = contract_attrs;
> +      return;
> +    }
> +  tree last_attr = DECL_ATTRIBUTES (decl);
> +  while (TREE_CHAIN (last_attr))
> +    last_attr = TREE_CHAIN (last_attr);
> +  TREE_CHAIN (last_attr) = contract_attrs;

I think you want to use 'chainon' here.

> @@ -5498,10 +5863,17 @@ start_decl (const cp_declarator *declarator,
>  
>        if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
>           /* Aliases are definitions. */
> -         && !alias)
> +         && !alias
> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>         permerror (declarator->id_loc,
>                    "declaration of %q#D outside of class is not definition",
>                    decl);
> +      else if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
> +         /* Aliases are definitions. */
> +         && !alias
> +         && flag_contract_strict_declarations)
> +       warning_at (declarator->id_loc, OPT_fcontract_strict_declarations_,
> +                   "non-defining declaration of %q#D outside of class", decl);

Let's keep the same message for the two cases.

> +void
> +finish_function_contracts (tree fndecl, bool is_inline)

This function needs a comment.

> +/* 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;
> +  /* We never want to accidentally instantiate templates.  */
> +  if (code == TEMPLATE_DECL)
> +    return *tp; /* FIXME? */

In what context are you getting a TEMPLATE_DECL here?  I don't see how 
this would have an effect on instantiations.

> +/* Parse a conditional-expression.  */
> +/* FIXME: should callers use cp_parser_constant_expression?  */
> +
> +static cp_expr
> +cp_parser_conditional_expression (cp_parser *parser)
...
> +  /* FIXME: can we use constant_expression for this?  */
> +  cp_expr cond = cp_parser_conditional_expression (parser);

I don't think we want to use cp_parser_constant_expression for 
expressions that are not intended to be constant.

> +  bool finishing_guarded_p = true//!processing_template_decl

?

> +    /* FIXME: Is this going to leak?  */
> +    comment_str = xstrdup (expr_to_string (cond));

There's no need to strdup here (and free a few lines later); 
build_string_literal copies the bytes.  The return value of 
expr_to_string is in GC memory.

> +  /* If we have contracts, check that they're valid in this context.  */
> +  // FIXME: These aren't entirely correct.

How not?  Can local extern function decls have contract attributes?

> +  if (tree pre = lookup_attribute ("pre", contract_attrs))
> +    error_at (EXPR_LOCATION (TREE_VALUE (pre)),
> +             "preconditions cannot be statements");
> +  else if (tree post = lookup_attribute ("post", contract_attrs))
> +    error_at (EXPR_LOCATION (TREE_VALUE (post)),
> +             "postconditions cannot be statements");
> +
> +  /* FIXME: move fallthrough up here so it applies to decls/etc?  */

That would make sense.

> +  temp_override<tree> saved_cct(current_class_type);
> +  temp_override<tree> saved_ccp(current_class_ptr);
> +  temp_override<tree> saved_ccr(current_class_ref);

Are these actually needed?

> +++ b/gcc/tree-inline.c
> @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "ssa.h"
>  #include "cgraph.h"
>  #include "tree-pretty-print.h"
> +#include "cp/cp-tree.h"

Can't include cp-tree.h in a language-independent file.  We already call 
the tree-inline machinery from the front-end in clone_body; can't you do 
the same for contracts?

> +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 (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
> +         && DECL_NAME (t) != NULL_TREE
> +         && IDENTIFIER_POINTER (DECL_NAME (t)) != NULL
> +         && id_equal (DECL_NAME (t), "this"))

You can use is_this_parameter here.

> +             /* FIXME when we instatiate a template class with guarded
> +              * members, particularly guarded template members, the resulting
> +              * pre/post functions end up being inaccessible because their
> +              * template info's context is the original uninstantiated class.

This sounds like a significant functionality gap.  I'm guessing you want 
to reconsider the unshare_template approach.

> +// FIXME: are we sure we shouldn't just mangle or use some existing machinery?
> +static const char *
> +get_contracts_internal_decl_name (const char *ident)

Definitely use the mangling machinery.

> +      /* FIXME do we need magic to perfectly forward this so we don't clobber
> +        RVO/NRVO etc?  */

Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you want.

More soon.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-01-18 14:56                 ` Jason Merrill
@ 2021-03-01 13:12                   ` Jeff Chapman
  2021-03-26  2:53                     ` Jason Merrill
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Chapman @ 2021-03-01 13:12 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Andrew Sutton, gcc-patches

On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>> Ping. re:
>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>
>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>
> Why is some of the code in c-family?  From the modules merge there is
> now a cp_handle_option function that you could add the option handling
> to, and I don't see a reason for cxx-contracts.c to be in c-family/
> rather than cp/.

I've been pushing changes that address the points raised and wanted to
ping to see if there's more feedback and give a status summary. The
notable change is making sure the implementation plays nicely with
modules and a mangling change that did away with a good chunk of code.

The contracts code outside of cp/ has been moved into it, and the
contract attributes have been altered to work with language independent
handling code. More of the contracts code can probably still be moved to
cxx-contracts which I'll loop back to after other refactoring. The
naming, spelling, and comments (or lack thereof) have been addressed.

>> +set_decl_contracts (tree decl, tree contract_attrs)
> I think you want to use 'chainon' here.

>> +build_arg_list (tree fn)
> You can use is_this_parameter here.

Thanks; I knew of chainon but didn't think of it and is_this_parameter
is new to me. Always fun to delete code :)

>> +  /* If we have contracts, check that they're valid in this context.  */
>> +  // FIXME: These aren't entirely correct.
>
> How not?  Can local extern function decls have contract attributes?
>
>> +             /* FIXME when we instatiate a template class with guarded
>> +              * members, particularly guarded template members, the resulting
>> +              * pre/post functions end up being inaccessible because their
>> +              * template info's context is the original uninstantiated class.
>
> This sounds like a significant functionality gap.  I'm guessing you want
> to reconsider the unshare_template approach.
>
>> +      /* FIXME do we need magic to perfectly forward this so we don't clobber
>> +        RVO/NRVO etc?  */
>
> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you want.

These points are still being investigated and addressed; including them
for reference.

> More soon.

Please let me know what other issues need work.


Thank you!
Jeff Chapman

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-03-01 13:12                   ` Jeff Chapman
@ 2021-03-26  2:53                     ` Jason Merrill
  2021-04-30 17:44                       ` Jeff Chapman
  0 siblings, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2021-03-26  2:53 UTC (permalink / raw)
  To: Jeff Chapman; +Cc: Andrew Sutton, gcc-patches

On 3/1/21 8:12 AM, Jeff Chapman wrote:
> On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
>> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>>> Ping. re:
>>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>>
>>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>>
>> Why is some of the code in c-family?  From the modules merge there is
>> now a cp_handle_option function that you could add the option handling
>> to, and I don't see a reason for cxx-contracts.c to be in c-family/
>> rather than cp/.
> 
> I've been pushing changes that address the points raised and wanted to
> ping to see if there's more feedback and give a status summary. The
> notable change is making sure the implementation plays nicely with
> modules and a mangling change that did away with a good chunk of code.
> 
> The contracts code outside of cp/ has been moved into it, and the
> contract attributes have been altered to work with language independent
> handling code. More of the contracts code can probably still be moved to
> cxx-contracts which I'll loop back to after other refactoring. The
> naming, spelling, and comments (or lack thereof) have been addressed.

Sounds good.  I plan to get back to this when GCC 11 branches, which 
should be mid-April.

>>> +set_decl_contracts (tree decl, tree contract_attrs)
>> I think you want to use 'chainon' here.
> 
>>> +build_arg_list (tree fn)
>> You can use is_this_parameter here.
> 
> Thanks; I knew of chainon but didn't think of it and is_this_parameter
> is new to me. Always fun to delete code :)
> 
>>> +  /* If we have contracts, check that they're valid in this context.  */
>>> +  // FIXME: These aren't entirely correct.
>>
>> How not?  Can local extern function decls have contract attributes?
>>
>>> +             /* FIXME when we instatiate a template class with guarded
>>> +              * members, particularly guarded template members, the resulting
>>> +              * pre/post functions end up being inaccessible because their
>>> +              * template info's context is the original uninstantiated class.
>>
>> This sounds like a significant functionality gap.  I'm guessing you want
>> to reconsider the unshare_template approach.
>>
>>> +      /* FIXME do we need magic to perfectly forward this so we don't clobber
>>> +        RVO/NRVO etc?  */
>>
>> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you want.
> 
> These points are still being investigated and addressed; including them
> for reference.
> 
>> More soon.
> 
> Please let me know what other issues need work.
> 
> 
> Thank you!
> Jeff Chapman
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-03-26  2:53                     ` Jason Merrill
@ 2021-04-30 17:44                       ` Jeff Chapman
  2021-05-14 20:54                         ` Jason Merrill
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Chapman @ 2021-04-30 17:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Andrew Sutton, gcc-patches

Hello! Looping back around to this. re:
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567334.html

On 3/25/21, Jason Merrill <jason@redhat.com> wrote:
> On 3/1/21 8:12 AM, Jeff Chapman wrote:
>> On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
>>> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>>>> Ping. re:
>>>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>>>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>>>
>>>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>>>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>>>
>>> Why is some of the code in c-family?  From the modules merge there is
>>> now a cp_handle_option function that you could add the option handling
>>> to, and I don't see a reason for cxx-contracts.c to be in c-family/
>>> rather than cp/.
>>
>> I've been pushing changes that address the points raised and wanted to
>> ping to see if there's more feedback and give a status summary. The
>> notable change is making sure the implementation plays nicely with
>> modules and a mangling change that did away with a good chunk of code.
>>
>> The contracts code outside of cp/ has been moved into it, and the
>> contract attributes have been altered to work with language independent
>> handling code. More of the contracts code can probably still be moved to
>> cxx-contracts which I'll loop back to after other refactoring. The
>> naming, spelling, and comments (or lack thereof) have been addressed.
>
> Sounds good.  I plan to get back to this when GCC 11 branches, which
> should be mid-April.

Please let me know if you see any more issues when you pick it back up.
Particularly in modules interop, since I don't think you've had a chance
to look at that yet.

Completed another merge with master earlier this week which didn't bring
to light any new issues or regressions, but I'll keep on that :)

>>>> +  /* If we have contracts, check that they're valid in this context. */
>>>> +  // FIXME: These aren't entirely correct.
>>>
>>> How not?  Can local extern function decls have contract attributes?
>>>
>>>> +             /* FIXME when we instatiate a template class with guarded
>>>> +              * members, particularly guarded template members, the resulting
>>>> +              * pre/post functions end up being inaccessible because their
>>>> +              * template info's context is the original uninstantiated class.
>>>
>>> This sounds like a significant functionality gap.  I'm guessing you want
>>> to reconsider the unshare_template approach.
>>>
>>>> +      /* FIXME do we need magic to perfectly forward this so we don't clobber
>>>> +        RVO/NRVO etc?  */
>>>
>>> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you
>>> want.
>>
>> These points are still being investigated and addressed; including them
>> for reference.
>>
>>> More soon.
>>
>> Please let me know what other issues need work.

If there's anything I can do to make the process smoother please don't
hesitate to ask.

Thank you,
Jeff Chapman

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-04-30 17:44                       ` Jeff Chapman
@ 2021-05-14 20:54                         ` Jason Merrill
  2021-05-14 21:09                           ` Marek Polacek
  2021-05-17 22:06                           ` Jason Merrill
  0 siblings, 2 replies; 31+ messages in thread
From: Jason Merrill @ 2021-05-14 20:54 UTC (permalink / raw)
  To: Jeff Chapman; +Cc: Andrew Sutton, gcc-patches

On 4/30/21 1:44 PM, Jeff Chapman wrote:
> Hello! Looping back around to this. re:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567334.html
> 
> On 3/25/21, Jason Merrill <jason@redhat.com> wrote:
>> On 3/1/21 8:12 AM, Jeff Chapman wrote:
>>> On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
>>>> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>>>>> Ping. re:
>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>>>>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>>>>
>>>>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>>>>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>>>>
>>>> Why is some of the code in c-family?  From the modules merge there is
>>>> now a cp_handle_option function that you could add the option handling
>>>> to, and I don't see a reason for cxx-contracts.c to be in c-family/
>>>> rather than cp/.
>>>
>>> I've been pushing changes that address the points raised and wanted to
>>> ping to see if there's more feedback and give a status summary. The
>>> notable change is making sure the implementation plays nicely with
>>> modules and a mangling change that did away with a good chunk of code.
>>>
>>> The contracts code outside of cp/ has been moved into it, and the
>>> contract attributes have been altered to work with language independent
>>> handling code. More of the contracts code can probably still be moved to
>>> cxx-contracts which I'll loop back to after other refactoring. The
>>> naming, spelling, and comments (or lack thereof) have been addressed.
>>
>> Sounds good.  I plan to get back to this when GCC 11 branches, which
>> should be mid-April.
> 
> Please let me know if you see any more issues when you pick it back up.
> Particularly in modules interop, since I don't think you've had a chance
> to look at that yet.
> 
> Completed another merge with master earlier this week which didn't bring
> to light any new issues or regressions, but I'll keep on that :)
> 
>>>>> +  /* If we have contracts, check that they're valid in this context. */
>>>>> +  // FIXME: These aren't entirely correct.
>>>>
>>>> How not?  Can local extern function decls have contract attributes?
>>>>
>>>>> +             /* FIXME when we instatiate a template class with guarded
>>>>> +              * members, particularly guarded template members, the resulting
>>>>> +              * pre/post functions end up being inaccessible because their
>>>>> +              * template info's context is the original uninstantiated class.
>>>>
>>>> This sounds like a significant functionality gap.  I'm guessing you want
>>>> to reconsider the unshare_template approach.

One approach would be to only do the pre/post/guarded/unguarded 
transformation for a fully-instantiated function; a temploid function 
would leave the contracts as attributes.

>>>>> +      /* FIXME do we need magic to perfectly forward this so we don't clobber
>>>>> +        RVO/NRVO etc?  */
>>>>
>>>> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you
>>>> want.
>>>
>>> These points are still being investigated and addressed; including them
>>> for reference.

Any update?

>>>> More soon.
>>>
>>> Please let me know what other issues need work.
> 
> If there's anything I can do to make the process smoother please don't
> hesitate to ask.

Larger-scope comments:

Please add an overview of the implementation strategy to the top of 
cxx-contracts.c.  Particularly to discuss the why and how of 
pre/post/guarded/unguarded functions.

I'm confused by the approach to late parsing of contracts; it seems like 
you wait until the end of parsing the function to go back and parse the 
contracts.  Why not parse them sooner, along with nsdmis, noexcept, and 
function bodies?

Smaller-scope comments:

>> +       /* If we didn't build a check, insert a NOP so we don't leak
>> +          contracts into GENERIC.  */
>> +       *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node);

You can use void_node for the NOP.

>> +      error_at (EXPR_LOCATION (new_contract),
>> +               "mismatched contract condition in %s",
>> +               ctx == cmc_declaration ? "declaration" : "override");

This sort of build-up of diagnostic messages by substring replacement 
doesn't work very well for translations.  In general, don't use %s for 
inserting English text, only code strings that will be the same in all 
languages.

>> +  /* Remove the associated contracts and unchecked result, if any.  */
>> +  if (flag_contracts && TREE_CODE (newdecl) == FUNCTION_DECL)
>> +    {
>> +      remove_contract_attributes (newdecl);
>> +      set_contract_functions (newdecl, NULL_TREE, NULL_TREE);
>> +    }

Why bother removing attributes on a decl that's about to be freed?

Why did we set the contract functions above only to clear them now?

>>        if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
>>           /* Aliases are definitions. */
>> -         && !alias)
>> +         && !alias
>> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>>         permerror (declarator->id_loc,
>>                    "declaration of %q#D outside of class is not definition",
>>                    decl);
>> +      else if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
>> +         /* Aliases are definitions. */
>> +         && !alias
>> +         && flag_contract_strict_declarations)
>> +       warning_at (declarator->id_loc, OPT_fcontract_strict_declarations_,
>> +                   "declaration of %q#D outside of class is not definition",
>> +                   decl);

Let's share the common predicates.

>> +  /* FIXME: move fallthrough up here so it applies to decls/etc?  */

That seems unnecessary, we already warn and ignore fallthrough on a decl.

>> +int cp_contract_operand = 0;
>> +tree cp_contract_return_value = NULL_TREE;

These need to be saved/restored by push_to/pop_from_top_level somehow, 
so that they don't stay set when parsing the contract triggers template 
instantiation.  The best way is probably to add them to struct saved_scope.

> +      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))
> +       {
> +         attributes
> +           = cp_parser_contract_attribute_spec (parser, attr_name);
> +         goto finish_attrs;
> +       }

Let's move the name checking inside cp_parser_contract_attribute_spec, 
and make that function return null for a non-contract attribute.

> +  /* FIXME we can do this a lot more efficiently? Once per function for all of
> +   * its pre contracts, and then once per post contract? Is there an
> +   * appreciable difference? Or a way to simply rename the post ret val parm? *

You might want to share the context handling with late parsing of noexcept.

> +  /* Don't do access checking if it is a templated function.  */
> +  if (processing_template_decl)
> +    push_deferring_access_checks (dk_no_check);

Don't we already defer access checking for templated functions?

> +/* Return a copy of the FUNCTION_DECL IDECL with its own unshared 
> +   PARM_DECL and DECL_ATTRIBUTEs.  */
> +
> +static tree
> +copy_fn_decl (tree idecl)

Can you use, or at least share code with, the existing 
copy_fndecl_with_name?

> +  /* FIXME will later optimizations delete unused args to prevent extra arg
> +   * passing? do we care? */

It might be possible to leverage the optimizer's partial-inlining code 
for this, I don't know.  Probably not worth messing with now.

More soon.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-05-14 20:54                         ` Jason Merrill
@ 2021-05-14 21:09                           ` Marek Polacek
  2021-05-17 22:06                           ` Jason Merrill
  1 sibling, 0 replies; 31+ messages in thread
From: Marek Polacek @ 2021-05-14 21:09 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Chapman, Andrew Sutton, gcc-patches

On Fri, May 14, 2021 at 04:54:10PM -0400, Jason Merrill via Gcc-patches wrote:
> Please add an overview of the implementation strategy to the top of
> cxx-contracts.c.  Particularly to discuss the why and how of
> pre/post/guarded/unguarded functions.

And I think let's please name the file contracts.cc.

Marek


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-05-14 20:54                         ` Jason Merrill
  2021-05-14 21:09                           ` Marek Polacek
@ 2021-05-17 22:06                           ` Jason Merrill
  2021-05-28 13:18                             ` Jeff Chapman
  1 sibling, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2021-05-17 22:06 UTC (permalink / raw)
  To: Jeff Chapman; +Cc: Andrew Sutton, gcc-patches

On 5/14/21 4:54 PM, Jason Merrill wrote:
> On 4/30/21 1:44 PM, Jeff Chapman wrote:
>> Hello! Looping back around to this. re:
>> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567334.html
>>
>> On 3/25/21, Jason Merrill <jason@redhat.com> wrote:
>>> On 3/1/21 8:12 AM, Jeff Chapman wrote:
>>>> On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
>>>>> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>>>>>> Ping. re:
>>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>>>>>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>>>>>
>>>>>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>>>>>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>>>>>
>>>>> Why is some of the code in c-family?  From the modules merge there is
>>>>> now a cp_handle_option function that you could add the option handling
>>>>> to, and I don't see a reason for cxx-contracts.c to be in c-family/
>>>>> rather than cp/.
>>>>
>>>> I've been pushing changes that address the points raised and wanted to
>>>> ping to see if there's more feedback and give a status summary. The
>>>> notable change is making sure the implementation plays nicely with
>>>> modules and a mangling change that did away with a good chunk of code.
>>>>
>>>> The contracts code outside of cp/ has been moved into it, and the
>>>> contract attributes have been altered to work with language independent
>>>> handling code. More of the contracts code can probably still be 
>>>> moved to
>>>> cxx-contracts which I'll loop back to after other refactoring. The
>>>> naming, spelling, and comments (or lack thereof) have been addressed.
>>>
>>> Sounds good.  I plan to get back to this when GCC 11 branches, which
>>> should be mid-April.
>>
>> Please let me know if you see any more issues when you pick it back up.
>> Particularly in modules interop, since I don't think you've had a chance
>> to look at that yet.
>>
>> Completed another merge with master earlier this week which didn't bring
>> to light any new issues or regressions, but I'll keep on that :)
>>
>>>>>> +  /* If we have contracts, check that they're valid in this 
>>>>>> context. */
>>>>>> +  // FIXME: These aren't entirely correct.
>>>>>
>>>>> How not?  Can local extern function decls have contract attributes?
>>>>>
>>>>>> +             /* FIXME when we instatiate a template class with 
>>>>>> guarded
>>>>>> +              * members, particularly guarded template members, 
>>>>>> the resulting
>>>>>> +              * pre/post functions end up being inaccessible 
>>>>>> because their
>>>>>> +              * template info's context is the original 
>>>>>> uninstantiated class.
>>>>>
>>>>> This sounds like a significant functionality gap.  I'm guessing you 
>>>>> want
>>>>> to reconsider the unshare_template approach.
> 
> One approach would be to only do the pre/post/guarded/unguarded 
> transformation for a fully-instantiated function; a temploid function 
> would leave the contracts as attributes.
> 
>>>>>> +      /* FIXME do we need magic to perfectly forward this so we 
>>>>>> don't clobber
>>>>>> +        RVO/NRVO etc?  */
>>>>>
>>>>> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you
>>>>> want.
>>>>
>>>> These points are still being investigated and addressed; including them
>>>> for reference.
> 
> Any update?
> 
>>>>> More soon.
>>>>
>>>> Please let me know what other issues need work.
>>
>> If there's anything I can do to make the process smoother please don't
>> hesitate to ask.
> 
> Larger-scope comments:
> 
> Please add an overview of the implementation strategy to the top of 
> cxx-contracts.c.  Particularly to discuss the why and how of 
> pre/post/guarded/unguarded functions.

> I'm confused by the approach to late parsing of contracts; it seems like 
> you wait until the end of parsing the function to go back and parse the 
> contracts.  Why not parse them sooner, along with nsdmis, noexcept, and 
> function bodies?
> 
> Smaller-scope comments:
> 
>>> +       /* If we didn't build a check, insert a NOP so we don't leak
>>> +          contracts into GENERIC.  */
>>> +       *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node);
> 
> You can use void_node for the NOP.
> 
>>> +      error_at (EXPR_LOCATION (new_contract),
>>> +               "mismatched contract condition in %s",
>>> +               ctx == cmc_declaration ? "declaration" : "override");
> 
> This sort of build-up of diagnostic messages by substring replacement 
> doesn't work very well for translations.  In general, don't use %s for 
> inserting English text, only code strings that will be the same in all 
> languages.
> 
>>> +  /* Remove the associated contracts and unchecked result, if any.  */
>>> +  if (flag_contracts && TREE_CODE (newdecl) == FUNCTION_DECL)
>>> +    {
>>> +      remove_contract_attributes (newdecl);
>>> +      set_contract_functions (newdecl, NULL_TREE, NULL_TREE);
>>> +    }
> 
> Why bother removing attributes on a decl that's about to be freed?
> 
> Why did we set the contract functions above only to clear them now?
> 
>>>        if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
>>>           /* Aliases are definitions. */
>>> -         && !alias)
>>> +         && !alias
>>> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>>>         permerror (declarator->id_loc,
>>>                    "declaration of %q#D outside of class is not 
>>> definition",
>>>                    decl);
>>> +      else if (DECL_EXTERNAL (decl) && ! 
>>> DECL_TEMPLATE_SPECIALIZATION (decl)
>>> +         /* Aliases are definitions. */
>>> +         && !alias
>>> +         && flag_contract_strict_declarations)
>>> +       warning_at (declarator->id_loc, 
>>> OPT_fcontract_strict_declarations_,
>>> +                   "declaration of %q#D outside of class is not 
>>> definition",
>>> +                   decl);
> 
> Let's share the common predicates.
> 
>>> +  /* FIXME: move fallthrough up here so it applies to decls/etc?  */
> 
> That seems unnecessary, we already warn and ignore fallthrough on a decl.
> 
>>> +int cp_contract_operand = 0;
>>> +tree cp_contract_return_value = NULL_TREE;
> 
> These need to be saved/restored by push_to/pop_from_top_level somehow, 
> so that they don't stay set when parsing the contract triggers template 
> instantiation.  The best way is probably to add them to struct saved_scope.
> 
>> +      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))
>> +       {
>> +         attributes
>> +           = cp_parser_contract_attribute_spec (parser, attr_name);
>> +         goto finish_attrs;
>> +       }
> 
> Let's move the name checking inside cp_parser_contract_attribute_spec, 
> and make that function return null for a non-contract attribute.
> 
>> +  /* FIXME we can do this a lot more efficiently? Once per function 
>> for all of
>> +   * its pre contracts, and then once per post contract? Is there an
>> +   * appreciable difference? Or a way to simply rename the post ret 
>> val parm? *
> 
> You might want to share the context handling with late parsing of noexcept.
> 
>> +  /* Don't do access checking if it is a templated function.  */
>> +  if (processing_template_decl)
>> +    push_deferring_access_checks (dk_no_check);
> 
> Don't we already defer access checking for templated functions?
> 
>> +/* Return a copy of the FUNCTION_DECL IDECL with its own unshared +   
>> PARM_DECL and DECL_ATTRIBUTEs.  */
>> +
>> +static tree
>> +copy_fn_decl (tree idecl)
> 
> Can you use, or at least share code with, the existing 
> copy_fndecl_with_name?
> 
>> +  /* FIXME will later optimizations delete unused args to prevent 
>> extra arg
>> +   * passing? do we care? */
> 
> It might be possible to leverage the optimizer's partial-inlining code 
> for this, I don't know.  Probably not worth messing with now.
> 
> More soon.

More:

> +       if (semantic == CCS_ASSUME && !cp_tree_defined_p (c))
> +         break;

Another approach to this would be to evaluate an assume with a separate 
non_constant_p and within the lifetime of a 
uid_sensitive_constexpr_evaluation_sentinel.  But the way you have it is 
fine.

> +  /* Ignored contracts are never checked or assumed.  */
> +  if (semantic == CCS_IGNORE)
> +    return build1 (NOP_EXPR, void_type_node, integer_zero_node);

Another place you can use void_node.

> +static void
> +build_contract_handler_fn (tree contract,
> +                          contract_continuation cmode)

This function needs a comment, and a better name.  Maybe just 
build_contract_handler_fn_call.

> +/* Rewrite the post function decl of FNDECL, replacing the original undeduced
> +   return type with RETURN_TYPE.  */
> +
> +static void
> +apply_post_deduced_return_type (tree fndecl, tree return_type)

Can this share more code with apply_deduced_return_type?

> +  if (needs_post && DECL_POST_FN (current_function_decl) != error_mark_node)
> +    {
> +      vec<tree, va_gc> *args = build_arg_list (current_function_decl);
> +      if (DECL_UNCHECKED_RESULT (current_function_decl))
> +       vec_safe_push (args, expr); // FIXME do we need forward_parm or similar?
> +
> +      if (undeduced_auto_decl (DECL_POST_FN (current_function_decl)))
> +       apply_post_deduced_return_type (current_function_decl,
> +                                       TREE_TYPE (expr));
> +
> +      push_deferring_access_checks (dk_no_check);
> +      tree call = finish_call_expr (DECL_POST_FN (current_function_decl), &args,
> +                                   /*disallow_virtual=*/true,
> +                                   /*koenig_p=*/false,
> +                                   /*complain=*/tf_warning_or_error);
> +      gcc_assert (call != error_mark_node);
> +      pop_deferring_access_checks ();
> +
> +      /* Replace returned expression with call to post function.  */
> +      expr = call;
> +    }

This looks like you pass the returned expression as an argument to the 
post function instead of using it to initialize the return value.  That 
will break copy elision.

What if instead (for a class return type at least) you initialize the 
return value, then pass a reference to the return value to the post 
function?  Then you could also share the call to the post function 
between all returns.

> +       if (tree check = build_contract_check (stmt))
> +         {
> +           /* 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;

These shouldn't be set here, they should be set as part of building the 
call to the handler.  You should get that by changing build_call_expr to 
build_call_n...

> +  tree call = build_call_expr (violation_fn, 8, continue_mode, line_number,
> +                              file_name, function_name, comment,
> +                              level_str, role_str,
> +                              continuation);

...here.

> +  /* FIXME: It looks  like we have two bits of information for
> +     continuing.  Is this right?  */

I think this is no longer true since you dropped "always continue".

> +  char buf[1024 + 4]{};
> +  char *res = buf;
> +  size_t len = 1024;

This seems like a good place to use obstacks.

> +      int s = expstart.column - 1;
> +      int l = expend.column - expstart.column + 1;

So, l = expend.column - s?

> +++ b/libstdc++-v3/src/c++17/contract.cc

Hmm.  Contracts library support was in clause 17, which would mean this 
should go in libstdc++-v3/libsupc++ instead.  But it depends on 
string_view, which is not in clause 17.  This seems like a problem in 
the standardese.

> +      /* 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");

Do you have in mind that these functions are part of the ABI, or 
internal implementation details of the functions?  If the former, we 
need to give them a proper mangling.  If the latter, we can make them 
hidden symbols in the same COMDAT section with their guarded function 
like with constructor variants, and their mangling isn't important.  I'm 
still wondering why you split them out from the guarded function in the 
first place.

> +      remap_overrider_contracts (overrider, basefn);
> +      remap_overrider_contracts (DECL_PRE_FN (overrider), DECL_PRE_FN (basefn));
> +      remap_overrider_contracts (DECL_POST_FN (overrider), DECL_POST_FN (basefn));

Why three times?  Why copy the contracts from the guarded function to 
the pre/post functions?

> +/* Assertion role info.  */

This needs elaboration about what a role is.

A lot of the code in decl.c could move to cxx-contracts.c.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-05-17 22:06                           ` Jason Merrill
@ 2021-05-28 13:18                             ` Jeff Chapman
       [not found]                               ` <CAMJpcpX7zAbHr79sZefXRSn2bxFg+ei9YUzMoapShctq=TwgGQ@mail.gmail.com>
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Chapman @ 2021-05-28 13:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Andrew Sutton, gcc-patches

Hello again :)  Wanted to shoot a quick status update. Some github issues have
been created for points of feedback, and we've been working on addressing them.
A few changes have been pushed to the contracts-jac-alt branch, while there's
also an active more in depth rewrite branch. Some specific comments inline
below.

On 5/17/21, Jason Merrill <jason@redhat.com> wrote:
> On 5/14/21 4:54 PM, Jason Merrill wrote:
>> On 4/30/21 1:44 PM, Jeff Chapman wrote:
>>> Hello! Looping back around to this. re:
>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567334.html
>>>
>>> On 3/25/21, Jason Merrill <jason@redhat.com> wrote:
>>>> On 3/1/21 8:12 AM, Jeff Chapman wrote:
>>>>> On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
>>>>>> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>>>>>>> Ping. re:
>>>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>>>>>>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>>>>>>
>>>>>>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>>>>>>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>>>>>>
>>>>>> Why is some of the code in c-family?  From the modules merge there is
>>>>>> now a cp_handle_option function that you could add the option
>>>>>> handling
>>>>>> to, and I don't see a reason for cxx-contracts.c to be in c-family/
>>>>>> rather than cp/.
>>>>>
>>>>> I've been pushing changes that address the points raised and wanted to
>>>>> ping to see if there's more feedback and give a status summary. The
>>>>> notable change is making sure the implementation plays nicely with
>>>>> modules and a mangling change that did away with a good chunk of code.
>>>>>
>>>>> The contracts code outside of cp/ has been moved into it, and the
>>>>> contract attributes have been altered to work with language
>>>>> independent
>>>>> handling code. More of the contracts code can probably still be
>>>>> moved to
>>>>> cxx-contracts which I'll loop back to after other refactoring. The
>>>>> naming, spelling, and comments (or lack thereof) have been addressed.
>>>>
>>>> Sounds good.  I plan to get back to this when GCC 11 branches, which
>>>> should be mid-April.
>>>
>>> Please let me know if you see any more issues when you pick it back up.
>>> Particularly in modules interop, since I don't think you've had a chance
>>> to look at that yet.
>>>
>>> Completed another merge with master earlier this week which didn't bring
>>> to light any new issues or regressions, but I'll keep on that :)
>>>
>>>>>>> +  /* If we have contracts, check that they're valid in this
>>>>>>> context. */
>>>>>>> +  // FIXME: These aren't entirely correct.
>>>>>>
>>>>>> How not?  Can local extern function decls have contract attributes?
>>>>>>
>>>>>>> +             /* FIXME when we instatiate a template class with
>>>>>>> guarded
>>>>>>> +              * members, particularly guarded template members,
>>>>>>> the resulting
>>>>>>> +              * pre/post functions end up being inaccessible
>>>>>>> because their
>>>>>>> +              * template info's context is the original
>>>>>>> uninstantiated class.
>>>>>>
>>>>>> This sounds like a significant functionality gap.  I'm guessing you
>>>>>> want
>>>>>> to reconsider the unshare_template approach.
>>
>> One approach would be to only do the pre/post/guarded/unguarded
>> transformation for a fully-instantiated function; a temploid function
>> would leave the contracts as attributes.
>>

There's an in progress rewrite which moves pre/post function generation until
much later which should resolve this. Like you suggested, these are not created
until we're completely out of template processing.

>>>>>>> +      /* FIXME do we need magic to perfectly forward this so we
>>>>>>> don't clobber
>>>>>>> +        RVO/NRVO etc?  */
>>>>>>
>>>>>> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you
>>>>>> want.
>>>>>
>>>>> These points are still being investigated and addressed; including
>>>>> them
>>>>> for reference.
>>
>> Any update?
>>

CALL_FROM_THUNK_P is being set now when an actual call is built. Is there a good
way to test that the optimization isn't being broken in general?

>>>>>> More soon.
>>>>>
>>>>> Please let me know what other issues need work.
>>>
>>> If there's anything I can do to make the process smoother please don't
>>> hesitate to ask.
>>
>> Larger-scope comments:
>>
>> Please add an overview of the implementation strategy to the top of
>> cxx-contracts.c.  Particularly to discuss the why and how of
>> pre/post/guarded/unguarded functions.

An initial overview has been added, though it'll need updated with some of the
pending rewrites.

>
>> I'm confused by the approach to late parsing of contracts; it seems like
>> you wait until the end of parsing the function to go back and parse the
>> contracts.  Why not parse them sooner, along with nsdmis, noexcept, and
>> function bodies?

Parsing has been moved forward on the rewrite branch.

>>
>> Smaller-scope comments:
>>
>>>> +       /* If we didn't build a check, insert a NOP so we don't leak
>>>> +          contracts into GENERIC.  */
>>>> +       *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node);
>>
>> You can use void_node for the NOP.
>>
>>>> +      error_at (EXPR_LOCATION (new_contract),
>>>> +               "mismatched contract condition in %s",
>>>> +               ctx == cmc_declaration ? "declaration" : "override");
>>
>> This sort of build-up of diagnostic messages by substring replacement
>> doesn't work very well for translations.  In general, don't use %s for
>> inserting English text, only code strings that will be the same in all
>> languages.
>>
>>>> +  /* Remove the associated contracts and unchecked result, if any.  */
>>>> +  if (flag_contracts && TREE_CODE (newdecl) == FUNCTION_DECL)
>>>> +    {
>>>> +      remove_contract_attributes (newdecl);
>>>> +      set_contract_functions (newdecl, NULL_TREE, NULL_TREE);
>>>> +    }
>>
>> Why bother removing attributes on a decl that's about to be freed?
>>
>> Why did we set the contract functions above only to clear them now?

Because the pre/post FUNCTION_DECLs are in a parallel map rather than being a
part of the original FUNCTION_DECL itself, this was to prevent the potentially
reused newdecl from already being associated with the wrong functions if it
also had contracts. Moot now though :)

>>
>>>>        if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION
>>>> (decl)
>>>>           /* Aliases are definitions. */
>>>> -         && !alias)
>>>> +         && !alias
>>>> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>>>>         permerror (declarator->id_loc,
>>>>                    "declaration of %q#D outside of class is not
>>>> definition",
>>>>                    decl);
>>>> +      else if (DECL_EXTERNAL (decl) && !
>>>> DECL_TEMPLATE_SPECIALIZATION (decl)
>>>> +         /* Aliases are definitions. */
>>>> +         && !alias
>>>> +         && flag_contract_strict_declarations)
>>>> +       warning_at (declarator->id_loc,
>>>> OPT_fcontract_strict_declarations_,
>>>> +                   "declaration of %q#D outside of class is not
>>>> definition",
>>>> +                   decl);
>>
>> Let's share the common predicates.
>>
>>>> +  /* FIXME: move fallthrough up here so it applies to decls/etc?  */
>>
>> That seems unnecessary, we already warn and ignore fallthrough on a decl.
>>
>>>> +int cp_contract_operand = 0;
>>>> +tree cp_contract_return_value = NULL_TREE;
>>
>> These need to be saved/restored by push_to/pop_from_top_level somehow,
>> so that they don't stay set when parsing the contract triggers template
>> instantiation.  The best way is probably to add them to struct
>> saved_scope.
>>
>>> +      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))
>>> +       {
>>> +         attributes
>>> +           = cp_parser_contract_attribute_spec (parser, attr_name);
>>> +         goto finish_attrs;
>>> +       }
>>
>> Let's move the name checking inside cp_parser_contract_attribute_spec,
>> and make that function return null for a non-contract attribute.
>>
>>> +  /* FIXME we can do this a lot more efficiently? Once per function
>>> for all of
>>> +   * its pre contracts, and then once per post contract? Is there an
>>> +   * appreciable difference? Or a way to simply rename the post ret
>>> val parm? *
>>
>> You might want to share the context handling with late parsing of
>> noexcept.
>>
>>> +  /* Don't do access checking if it is a templated function.  */
>>> +  if (processing_template_decl)
>>> +    push_deferring_access_checks (dk_no_check);
>>
>> Don't we already defer access checking for templated functions?
>>
>>> +/* Return a copy of the FUNCTION_DECL IDECL with its own unshared +
>>> PARM_DECL and DECL_ATTRIBUTEs.  */
>>> +
>>> +static tree
>>> +copy_fn_decl (tree idecl)
>>
>> Can you use, or at least share code with, the existing
>> copy_fndecl_with_name?
>>
>>> +  /* FIXME will later optimizations delete unused args to prevent
>>> extra arg
>>> +   * passing? do we care? */
>>
>> It might be possible to leverage the optimizer's partial-inlining code
>> for this, I don't know.  Probably not worth messing with now.
>>
>> More soon.
>
> More:
>
>> +       if (semantic == CCS_ASSUME && !cp_tree_defined_p (c))
>> +         break;
>
> Another approach to this would be to evaluate an assume with a separate
> non_constant_p and within the lifetime of a
> uid_sensitive_constexpr_evaluation_sentinel.  But the way you have it is
> fine.
>
>> +  /* Ignored contracts are never checked or assumed.  */
>> +  if (semantic == CCS_IGNORE)
>> +    return build1 (NOP_EXPR, void_type_node, integer_zero_node);
>
> Another place you can use void_node.
>
>> +static void
>> +build_contract_handler_fn (tree contract,
>> +                          contract_continuation cmode)
>
> This function needs a comment, and a better name.  Maybe just
> build_contract_handler_fn_call.
>
>> +/* Rewrite the post function decl of FNDECL, replacing the original
>> undeduced
>> +   return type with RETURN_TYPE.  */
>> +
>> +static void
>> +apply_post_deduced_return_type (tree fndecl, tree return_type)
>
> Can this share more code with apply_deduced_return_type?
>
>> +  if (needs_post && DECL_POST_FN (current_function_decl) !=
>> error_mark_node)
>> +    {
>> +      vec<tree, va_gc> *args = build_arg_list (current_function_decl);
>> +      if (DECL_UNCHECKED_RESULT (current_function_decl))
>> +       vec_safe_push (args, expr); // FIXME do we need forward_parm or
>> similar?
>> +
>> +      if (undeduced_auto_decl (DECL_POST_FN (current_function_decl)))
>> +       apply_post_deduced_return_type (current_function_decl,
>> +                                       TREE_TYPE (expr));
>> +
>> +      push_deferring_access_checks (dk_no_check);
>> +      tree call = finish_call_expr (DECL_POST_FN (current_function_decl),
>> &args,
>> +                                   /*disallow_virtual=*/true,
>> +                                   /*koenig_p=*/false,
>> +                                   /*complain=*/tf_warning_or_error);
>> +      gcc_assert (call != error_mark_node);
>> +      pop_deferring_access_checks ();
>> +
>> +      /* Replace returned expression with call to post function.  */
>> +      expr = call;
>> +    }
>
> This looks like you pass the returned expression as an argument to the
> post function instead of using it to initialize the return value.  That
> will break copy elision.
>
> What if instead (for a class return type at least) you initialize the
> return value, then pass a reference to the return value to the post
> function?  Then you could also share the call to the post function
> between all returns.
>
>> +       if (tree check = build_contract_check (stmt))
>> +         {
>> +           /* 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;
>
> These shouldn't be set here, they should be set as part of building the
> call to the handler.  You should get that by changing build_call_expr to
> build_call_n...
>
>> +  tree call = build_call_expr (violation_fn, 8, continue_mode,
>> line_number,
>> +                              file_name, function_name, comment,
>> +                              level_str, role_str,
>> +                              continuation);
>
> ...here.
>
>> +  /* FIXME: It looks  like we have two bits of information for
>> +     continuing.  Is this right?  */
>
> I think this is no longer true since you dropped "always continue".
>
>> +  char buf[1024 + 4]{};
>> +  char *res = buf;
>> +  size_t len = 1024;
>
> This seems like a good place to use obstacks.
>
>> +      int s = expstart.column - 1;
>> +      int l = expend.column - expstart.column + 1;
>
> So, l = expend.column - s?
>

Changes to get_source to use obstacks and cleanup some of the math are also
sitting on a branch and will be cherry-picked once the rewrite is stable.

>> +++ b/libstdc++-v3/src/c++17/contract.cc
>
> Hmm.  Contracts library support was in clause 17, which would mean this
> should go in libstdc++-v3/libsupc++ instead.  But it depends on
> string_view, which is not in clause 17.  This seems like a problem in
> the standardese.
>
>> +      /* 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");
>
> Do you have in mind that these functions are part of the ABI, or
> internal implementation details of the functions?  If the former, we
> need to give them a proper mangling.  If the latter, we can make them
> hidden symbols in the same COMDAT section with their guarded function
> like with constructor variants, and their mangling isn't important.  I'm
> still wondering why you split them out from the guarded function in the
> first place.
>

Ditto. These are currently internal implementation details so they've been made
hidden. Future extensions to contracts might result in this being revisited.

>> +      remap_overrider_contracts (overrider, basefn);
>> +      remap_overrider_contracts (DECL_PRE_FN (overrider), DECL_PRE_FN
>> (basefn));
>> +      remap_overrider_contracts (DECL_POST_FN (overrider), DECL_POST_FN
>> (basefn));
>
> Why three times?  Why copy the contracts from the guarded function to
> the pre/post functions?

This is fixed in the rewrite branch.

>
>> +/* Assertion role info.  */
>
> This needs elaboration about what a role is.
>
> A lot of the code in decl.c could move to cxx-contracts.c.
>
> Jason
>
>

Please let us know if there are other issues, or if it sounds like we're not
headed in the correct direction.

Thank you,
Jeff Chapman

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
       [not found]                               ` <CAMJpcpX7zAbHr79sZefXRSn2bxFg+ei9YUzMoapShctq=TwgGQ@mail.gmail.com>
@ 2021-07-01 15:14                                 ` Jason Merrill
  2021-07-01 16:27                                   ` Andrew Sutton
  2021-07-05 19:07                                 ` contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts) Jason Merrill
  1 sibling, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2021-07-01 15:14 UTC (permalink / raw)
  To: Andrew Sutton; +Cc: gcc-patches, Jeff Chapman

On 6/26/21 10:23 AM, Andrew Sutton wrote:
> Hi Jason,
> 
> I ended up taking over this work from Jeff (CC'd on his existing email
> address). I scraped all the contracts changes into one big patch
> against master. See attached. The ChangeLog.contracts files list the
> sum of changes for the patch, not the full history of the work.
> 
> I think this version addresses most of your concerns.

Thanks, looking good.  I'll fuss with it a bit and commit it soon.

> There are a few big changes.
> 
> The first is that we treat contracts like any other attribute, which
> gets interesting at times. For example, in duplicate_decl, we have to
> do a little dance to make sure the target merge_attributes doesn't
> copy attributes between the new and old decls in seemingly arbitrary
> order. Friends are also a bit funny because the attributes aren't
> attached by cplus_decl_attributes at the point declarations are
> merged, so we have to defer comparisons.
> 
> Contracts are always parsed where they appear, except on member
> functions. For postconditions with result variables (e.g., [[post r:
> ...]]), we temporarily declare r as if 'auto r' and then update it
> later when we've computed the function's return type. (I feel like
> this was kind of overlooked in N4820... it's generally impossible to
> assign a type to 'r' given the position of contract attributes in the
> declarator: 'auto f(int n) [[post r: q]] -> int'. It's worse in GCC
> since the return type is computed in grokdeclarator, well after
> contract attributes have been parsed).
> 
> On a related note, the handling of postconditions involving deduced
> return type was completely rewritten. Everything happens in
> apply_deduced_return_type, which seems right. I think
> check_return_expr is where the postcondition is actually invoked.
> 
> We no longer instantiate contract attributes until absolutely
> necessary in regenerate_decl_from_tempalte. That seems to work well...
> at least does after I discovered we were quietly rewriting contract
> lists every time we removed contracts from an old declaration or from
> a template specialization. This also gets rid of the need to have
> unshare_templates, which had a FIXME note attached.
> 
> Lastly, we only ever generate pre/post checks for actual functions,
> not function templates. I also simplified a lot of the logic around
> associating pre/post check functions, so that it's only set exactly
> once when start analyzing function definitions.
> 
> I believe Jeff addressed some of the ABI concerns and COMDAT-related questions.
> 
> On the issue of copy_fn_decl vs.v copy_fndecl_with_name... I didn't
> change that. The latter sends the function to middle end for codegen,
> which we really don't want at the point we make the copy.
> 
> I think we're probably still breaking NRVO. I didn't get a chance to
> look at that.

> On Fri, May 28, 2021 at 9:18 AM Jeff Chapman <jchapman@lock3software.com> wrote:
>>
>> Hello again :)  Wanted to shoot a quick status update. Some github issues have
>> been created for points of feedback, and we've been working on addressing them.
>> A few changes have been pushed to the contracts-jac-alt branch, while there's
>> also an active more in depth rewrite branch. Some specific comments inline
>> below.
>>
>> On 5/17/21, Jason Merrill <jason@redhat.com> wrote:
>>> On 5/14/21 4:54 PM, Jason Merrill wrote:
>>>> On 4/30/21 1:44 PM, Jeff Chapman wrote:
>>>>> Hello! Looping back around to this. re:
>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567334.html
>>>>>
>>>>> On 3/25/21, Jason Merrill <jason@redhat.com> wrote:
>>>>>> On 3/1/21 8:12 AM, Jeff Chapman wrote:
>>>>>>> On 1/18/21, Jason Merrill <jason@redhat.com> wrote:
>>>>>>>> On 1/4/21 9:58 AM, Jeff Chapman wrote:
>>>>>>>>> Ping. re:
>>>>>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html
>>>>>>>>> <https://gcc.gnu.org/pipermail/gcc-patches/2020-December/561135.html>
>>>>>>>>>
>>>>>>>>> https://github.com/lock3/gcc/tree/contracts-jac-alt
>>>>>>>>> <https://github.com/lock3/gcc/tree/contracts-jac-alt>
>>>>>>>>>
>>>>>>>> Why is some of the code in c-family?  From the modules merge there is
>>>>>>>> now a cp_handle_option function that you could add the option
>>>>>>>> handling
>>>>>>>> to, and I don't see a reason for cxx-contracts.c to be in c-family/
>>>>>>>> rather than cp/.
>>>>>>>
>>>>>>> I've been pushing changes that address the points raised and wanted to
>>>>>>> ping to see if there's more feedback and give a status summary. The
>>>>>>> notable change is making sure the implementation plays nicely with
>>>>>>> modules and a mangling change that did away with a good chunk of code.
>>>>>>>
>>>>>>> The contracts code outside of cp/ has been moved into it, and the
>>>>>>> contract attributes have been altered to work with language
>>>>>>> independent
>>>>>>> handling code. More of the contracts code can probably still be
>>>>>>> moved to
>>>>>>> cxx-contracts which I'll loop back to after other refactoring. The
>>>>>>> naming, spelling, and comments (or lack thereof) have been addressed.
>>>>>>
>>>>>> Sounds good.  I plan to get back to this when GCC 11 branches, which
>>>>>> should be mid-April.
>>>>>
>>>>> Please let me know if you see any more issues when you pick it back up.
>>>>> Particularly in modules interop, since I don't think you've had a chance
>>>>> to look at that yet.
>>>>>
>>>>> Completed another merge with master earlier this week which didn't bring
>>>>> to light any new issues or regressions, but I'll keep on that :)
>>>>>
>>>>>>>>> +  /* If we have contracts, check that they're valid in this
>>>>>>>>> context. */
>>>>>>>>> +  // FIXME: These aren't entirely correct.
>>>>>>>>
>>>>>>>> How not?  Can local extern function decls have contract attributes?
>>>>>>>>
>>>>>>>>> +             /* FIXME when we instatiate a template class with
>>>>>>>>> guarded
>>>>>>>>> +              * members, particularly guarded template members,
>>>>>>>>> the resulting
>>>>>>>>> +              * pre/post functions end up being inaccessible
>>>>>>>>> because their
>>>>>>>>> +              * template info's context is the original
>>>>>>>>> uninstantiated class.
>>>>>>>>
>>>>>>>> This sounds like a significant functionality gap.  I'm guessing you
>>>>>>>> want
>>>>>>>> to reconsider the unshare_template approach.
>>>>
>>>> One approach would be to only do the pre/post/guarded/unguarded
>>>> transformation for a fully-instantiated function; a temploid function
>>>> would leave the contracts as attributes.
>>>>
>>
>> There's an in progress rewrite which moves pre/post function generation until
>> much later which should resolve this. Like you suggested, these are not created
>> until we're completely out of template processing.
>>
>>>>>>>>> +      /* FIXME do we need magic to perfectly forward this so we
>>>>>>>>> don't clobber
>>>>>>>>> +        RVO/NRVO etc?  */
>>>>>>>>
>>>>>>>> Yes.  CALL_FROM_THUNK_P will probably get you some of the magic you
>>>>>>>> want.
>>>>>>>
>>>>>>> These points are still being investigated and addressed; including
>>>>>>> them
>>>>>>> for reference.
>>>>
>>>> Any update?
>>>>
>>
>> CALL_FROM_THUNK_P is being set now when an actual call is built. Is there a good
>> way to test that the optimization isn't being broken in general?
>>
>>>>>>>> More soon.
>>>>>>>
>>>>>>> Please let me know what other issues need work.
>>>>>
>>>>> If there's anything I can do to make the process smoother please don't
>>>>> hesitate to ask.
>>>>
>>>> Larger-scope comments:
>>>>
>>>> Please add an overview of the implementation strategy to the top of
>>>> cxx-contracts.c.  Particularly to discuss the why and how of
>>>> pre/post/guarded/unguarded functions.
>>
>> An initial overview has been added, though it'll need updated with some of the
>> pending rewrites.
>>
>>>
>>>> I'm confused by the approach to late parsing of contracts; it seems like
>>>> you wait until the end of parsing the function to go back and parse the
>>>> contracts.  Why not parse them sooner, along with nsdmis, noexcept, and
>>>> function bodies?
>>
>> Parsing has been moved forward on the rewrite branch.
>>
>>>>
>>>> Smaller-scope comments:
>>>>
>>>>>> +       /* If we didn't build a check, insert a NOP so we don't leak
>>>>>> +          contracts into GENERIC.  */
>>>>>> +       *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node);
>>>>
>>>> You can use void_node for the NOP.
>>>>
>>>>>> +      error_at (EXPR_LOCATION (new_contract),
>>>>>> +               "mismatched contract condition in %s",
>>>>>> +               ctx == cmc_declaration ? "declaration" : "override");
>>>>
>>>> This sort of build-up of diagnostic messages by substring replacement
>>>> doesn't work very well for translations.  In general, don't use %s for
>>>> inserting English text, only code strings that will be the same in all
>>>> languages.
>>>>
>>>>>> +  /* Remove the associated contracts and unchecked result, if any.  */
>>>>>> +  if (flag_contracts && TREE_CODE (newdecl) == FUNCTION_DECL)
>>>>>> +    {
>>>>>> +      remove_contract_attributes (newdecl);
>>>>>> +      set_contract_functions (newdecl, NULL_TREE, NULL_TREE);
>>>>>> +    }
>>>>
>>>> Why bother removing attributes on a decl that's about to be freed?
>>>>
>>>> Why did we set the contract functions above only to clear them now?
>>
>> Because the pre/post FUNCTION_DECLs are in a parallel map rather than being a
>> part of the original FUNCTION_DECL itself, this was to prevent the potentially
>> reused newdecl from already being associated with the wrong functions if it
>> also had contracts. Moot now though :)
>>
>>>>
>>>>>>         if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION
>>>>>> (decl)
>>>>>>            /* Aliases are definitions. */
>>>>>> -         && !alias)
>>>>>> +         && !alias
>>>>>> +         && (DECL_VIRTUAL_P (decl) || !flag_contracts))
>>>>>>          permerror (declarator->id_loc,
>>>>>>                     "declaration of %q#D outside of class is not
>>>>>> definition",
>>>>>>                     decl);
>>>>>> +      else if (DECL_EXTERNAL (decl) && !
>>>>>> DECL_TEMPLATE_SPECIALIZATION (decl)
>>>>>> +         /* Aliases are definitions. */
>>>>>> +         && !alias
>>>>>> +         && flag_contract_strict_declarations)
>>>>>> +       warning_at (declarator->id_loc,
>>>>>> OPT_fcontract_strict_declarations_,
>>>>>> +                   "declaration of %q#D outside of class is not
>>>>>> definition",
>>>>>> +                   decl);
>>>>
>>>> Let's share the common predicates.
>>>>
>>>>>> +  /* FIXME: move fallthrough up here so it applies to decls/etc?  */
>>>>
>>>> That seems unnecessary, we already warn and ignore fallthrough on a decl.
>>>>
>>>>>> +int cp_contract_operand = 0;
>>>>>> +tree cp_contract_return_value = NULL_TREE;
>>>>
>>>> These need to be saved/restored by push_to/pop_from_top_level somehow,
>>>> so that they don't stay set when parsing the contract triggers template
>>>> instantiation.  The best way is probably to add them to struct
>>>> saved_scope.
>>>>
>>>>> +      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))
>>>>> +       {
>>>>> +         attributes
>>>>> +           = cp_parser_contract_attribute_spec (parser, attr_name);
>>>>> +         goto finish_attrs;
>>>>> +       }
>>>>
>>>> Let's move the name checking inside cp_parser_contract_attribute_spec,
>>>> and make that function return null for a non-contract attribute.
>>>>
>>>>> +  /* FIXME we can do this a lot more efficiently? Once per function
>>>>> for all of
>>>>> +   * its pre contracts, and then once per post contract? Is there an
>>>>> +   * appreciable difference? Or a way to simply rename the post ret
>>>>> val parm? *
>>>>
>>>> You might want to share the context handling with late parsing of
>>>> noexcept.
>>>>
>>>>> +  /* Don't do access checking if it is a templated function.  */
>>>>> +  if (processing_template_decl)
>>>>> +    push_deferring_access_checks (dk_no_check);
>>>>
>>>> Don't we already defer access checking for templated functions?
>>>>
>>>>> +/* Return a copy of the FUNCTION_DECL IDECL with its own unshared +
>>>>> PARM_DECL and DECL_ATTRIBUTEs.  */
>>>>> +
>>>>> +static tree
>>>>> +copy_fn_decl (tree idecl)
>>>>
>>>> Can you use, or at least share code with, the existing
>>>> copy_fndecl_with_name?
>>>>
>>>>> +  /* FIXME will later optimizations delete unused args to prevent
>>>>> extra arg
>>>>> +   * passing? do we care? */
>>>>
>>>> It might be possible to leverage the optimizer's partial-inlining code
>>>> for this, I don't know.  Probably not worth messing with now.
>>>>
>>>> More soon.
>>>
>>> More:
>>>
>>>> +       if (semantic == CCS_ASSUME && !cp_tree_defined_p (c))
>>>> +         break;
>>>
>>> Another approach to this would be to evaluate an assume with a separate
>>> non_constant_p and within the lifetime of a
>>> uid_sensitive_constexpr_evaluation_sentinel.  But the way you have it is
>>> fine.
>>>
>>>> +  /* Ignored contracts are never checked or assumed.  */
>>>> +  if (semantic == CCS_IGNORE)
>>>> +    return build1 (NOP_EXPR, void_type_node, integer_zero_node);
>>>
>>> Another place you can use void_node.
>>>
>>>> +static void
>>>> +build_contract_handler_fn (tree contract,
>>>> +                          contract_continuation cmode)
>>>
>>> This function needs a comment, and a better name.  Maybe just
>>> build_contract_handler_fn_call.
>>>
>>>> +/* Rewrite the post function decl of FNDECL, replacing the original
>>>> undeduced
>>>> +   return type with RETURN_TYPE.  */
>>>> +
>>>> +static void
>>>> +apply_post_deduced_return_type (tree fndecl, tree return_type)
>>>
>>> Can this share more code with apply_deduced_return_type?
>>>
>>>> +  if (needs_post && DECL_POST_FN (current_function_decl) !=
>>>> error_mark_node)
>>>> +    {
>>>> +      vec<tree, va_gc> *args = build_arg_list (current_function_decl);
>>>> +      if (DECL_UNCHECKED_RESULT (current_function_decl))
>>>> +       vec_safe_push (args, expr); // FIXME do we need forward_parm or
>>>> similar?
>>>> +
>>>> +      if (undeduced_auto_decl (DECL_POST_FN (current_function_decl)))
>>>> +       apply_post_deduced_return_type (current_function_decl,
>>>> +                                       TREE_TYPE (expr));
>>>> +
>>>> +      push_deferring_access_checks (dk_no_check);
>>>> +      tree call = finish_call_expr (DECL_POST_FN (current_function_decl),
>>>> &args,
>>>> +                                   /*disallow_virtual=*/true,
>>>> +                                   /*koenig_p=*/false,
>>>> +                                   /*complain=*/tf_warning_or_error);
>>>> +      gcc_assert (call != error_mark_node);
>>>> +      pop_deferring_access_checks ();
>>>> +
>>>> +      /* Replace returned expression with call to post function.  */
>>>> +      expr = call;
>>>> +    }
>>>
>>> This looks like you pass the returned expression as an argument to the
>>> post function instead of using it to initialize the return value.  That
>>> will break copy elision.
>>>
>>> What if instead (for a class return type at least) you initialize the
>>> return value, then pass a reference to the return value to the post
>>> function?  Then you could also share the call to the post function
>>> between all returns.
>>>
>>>> +       if (tree check = build_contract_check (stmt))
>>>> +         {
>>>> +           /* 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;
>>>
>>> These shouldn't be set here, they should be set as part of building the
>>> call to the handler.  You should get that by changing build_call_expr to
>>> build_call_n...
>>>
>>>> +  tree call = build_call_expr (violation_fn, 8, continue_mode,
>>>> line_number,
>>>> +                              file_name, function_name, comment,
>>>> +                              level_str, role_str,
>>>> +                              continuation);
>>>
>>> ...here.
>>>
>>>> +  /* FIXME: It looks  like we have two bits of information for
>>>> +     continuing.  Is this right?  */
>>>
>>> I think this is no longer true since you dropped "always continue".
>>>
>>>> +  char buf[1024 + 4]{};
>>>> +  char *res = buf;
>>>> +  size_t len = 1024;
>>>
>>> This seems like a good place to use obstacks.
>>>
>>>> +      int s = expstart.column - 1;
>>>> +      int l = expend.column - expstart.column + 1;
>>>
>>> So, l = expend.column - s?
>>>
>>
>> Changes to get_source to use obstacks and cleanup some of the math are also
>> sitting on a branch and will be cherry-picked once the rewrite is stable.
>>
>>>> +++ b/libstdc++-v3/src/c++17/contract.cc
>>>
>>> Hmm.  Contracts library support was in clause 17, which would mean this
>>> should go in libstdc++-v3/libsupc++ instead.  But it depends on
>>> string_view, which is not in clause 17.  This seems like a problem in
>>> the standardese.
>>>
>>>> +      /* 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");
>>>
>>> Do you have in mind that these functions are part of the ABI, or
>>> internal implementation details of the functions?  If the former, we
>>> need to give them a proper mangling.  If the latter, we can make them
>>> hidden symbols in the same COMDAT section with their guarded function
>>> like with constructor variants, and their mangling isn't important.  I'm
>>> still wondering why you split them out from the guarded function in the
>>> first place.
>>>
>>
>> Ditto. These are currently internal implementation details so they've been made
>> hidden. Future extensions to contracts might result in this being revisited.
>>
>>>> +      remap_overrider_contracts (overrider, basefn);
>>>> +      remap_overrider_contracts (DECL_PRE_FN (overrider), DECL_PRE_FN
>>>> (basefn));
>>>> +      remap_overrider_contracts (DECL_POST_FN (overrider), DECL_POST_FN
>>>> (basefn));
>>>
>>> Why three times?  Why copy the contracts from the guarded function to
>>> the pre/post functions?
>>
>> This is fixed in the rewrite branch.
>>
>>>
>>>> +/* Assertion role info.  */
>>>
>>> This needs elaboration about what a role is.
>>>
>>> A lot of the code in decl.c could move to cxx-contracts.c.
>>>
>>> Jason
>>>
>>>
>>
>> Please let us know if there are other issues, or if it sounds like we're not
>> headed in the correct direction.
>>
>> Thank you,
>> Jeff Chapman


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-07-01 15:14                                 ` Jason Merrill
@ 2021-07-01 16:27                                   ` Andrew Sutton
  2021-07-02 15:09                                     ` Jason Merrill
  0 siblings, 1 reply; 31+ messages in thread
From: Andrew Sutton @ 2021-07-01 16:27 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Jeff Chapman

> > I think this version addresses most of your concerns.
>
> Thanks, looking good.  I'll fuss with it a bit and commit it soon.

Awesome!

Andrew

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-07-01 16:27                                   ` Andrew Sutton
@ 2021-07-02 15:09                                     ` Jason Merrill
  2021-07-02 15:30                                       ` Andrew Sutton
  0 siblings, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2021-07-02 15:09 UTC (permalink / raw)
  To: Andrew Sutton; +Cc: gcc-patches, Jeff Chapman

[-- Attachment #1: Type: text/plain, Size: 221 bytes --]

On 7/1/21 12:27 PM, Andrew Sutton wrote:
>>> I think this version addresses most of your concerns.
>>
>> Thanks, looking good.  I'll fuss with it a bit and commit it soon.

Do you agree that this testcase should compile?

[-- Attachment #2: 0001-assume-cx.patch --]
[-- Type: text/x-patch, Size: 2475 bytes --]

From 85400e1896a188892b1ebeb0c8e86ff3cd28cfa6 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Wed, 30 Jun 2021 16:57:44 -0400
Subject: [PATCH] assume-cx
To: gcc-patches@gcc.gnu.org

---
 gcc/cp/constexpr.c                            | 26 +++++++++++++++----
 .../g++.dg/contracts/contracts-constexpr3.C   | 10 +++++++
 2 files changed, 31 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/contracts/contracts-constexpr3.C

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 435bf530d68..66b3ccce713 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -7022,12 +7022,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  break;
 
 	tree c = CONTRACT_CONDITION (t);
-	if (semantic == CCS_ASSUME && !cp_tree_defined_p (c))
-	  break;
+	if (semantic == CCS_ASSUME)
+	  {
+	    /* For an assume contract, try evaluating it without instantiating
+	       anything.  If non-constant, assume it's satisfied.  */
 
-	/* Evaluate the generated check.  */
-	r = cxx_eval_constant_expression (ctx, c, false, non_constant_p,
-					  overflow_p);
+	    if (!cp_tree_defined_p (c))
+	      break;
+
+	    bool dummy_nc = false, dummy_ov = false;
+	    constexpr_ctx new_ctx = *ctx;
+	    new_ctx.quiet = true;
+	    r = cxx_eval_constant_expression (&new_ctx, c, false,
+					      &dummy_nc, &dummy_ov);
+	    if (dummy_nc)
+	      break;
+	  }
+	else
+	  /* 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)
@@ -8948,6 +8962,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case ASSERTION_STMT:
     case PRECONDITION_STMT:
     case POSTCONDITION_STMT:
+      if (!checked_contract_p (get_contract_semantic (t)))
+	return true;
       if (!RECUR (CONTRACT_CONDITION (t), rval))
 	return false;
       return true;
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-constexpr3.C b/gcc/testsuite/g++.dg/contracts/contracts-constexpr3.C
new file mode 100644
index 00000000000..8826220ef91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/contracts-constexpr3.C
@@ -0,0 +1,10 @@
+// An assumed contract shouldn't break constant evaluation.
+
+// { dg-do compile { target c++20 } }
+// { dg-additional-options -fcontracts }
+
+bool b;
+
+constexpr int f() [[ pre assume: b ]] { return 42; }
+
+static_assert (f() > 0);
-- 
2.27.0


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] PING implement pre-c++20 contracts
  2021-07-02 15:09                                     ` Jason Merrill
@ 2021-07-02 15:30                                       ` Andrew Sutton
  0 siblings, 0 replies; 31+ messages in thread
From: Andrew Sutton @ 2021-07-02 15:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Jeff Chapman

I think so, yes.

On Fri, Jul 2, 2021 at 11:09 AM Jason Merrill <jason@redhat.com> wrote:
>
> On 7/1/21 12:27 PM, Andrew Sutton wrote:
> >>> I think this version addresses most of your concerns.
> >>
> >> Thanks, looking good.  I'll fuss with it a bit and commit it soon.
>
> Do you agree that this testcase should compile?

^ permalink raw reply	[flat|nested] 31+ messages in thread

* contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
       [not found]                               ` <CAMJpcpX7zAbHr79sZefXRSn2bxFg+ei9YUzMoapShctq=TwgGQ@mail.gmail.com>
  2021-07-01 15:14                                 ` Jason Merrill
@ 2021-07-05 19:07                                 ` Jason Merrill
  2021-07-06 20:47                                   ` Jason Merrill
  2021-07-12 19:58                                   ` Jonathan Wakely
  1 sibling, 2 replies; 31+ messages in thread
From: Jason Merrill @ 2021-07-05 19:07 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches, Jeff Chapman, Andrew Sutton

On 6/26/21 10:23 AM, Andrew Sutton wrote:
> 
> I ended up taking over this work from Jeff (CC'd on his existing email
> address). I scraped all the contracts changes into one big patch
> against master. See attached. The ChangeLog.contracts files list the
> sum of changes for the patch, not the full history of the work.

Jonathan, can you advise where the library support should go?

In N4820 <contract> was part of the language-support clause, which makes 
sense, but it uses string_view, which brings in a lot of the rest of the 
library.  Did LWG talk about this when contracts went in?  How are 
freestanding implementations expected to support contracts?

I imagine the header should be <experimental/contract> for now.

You've previously mentioned that various current experimental features 
don't appear in libstdc++.so; that is not true of the current patch.

I see that https://github.com/arcosuc3m/clang-contracts takes the 
approach, of teaching the compiler about std::contract_violation, 
building up an object, and passing it to the handler directly, much like 
we do for initializer_list.  Their equivalent of __on_contract_violation 
is an internal function emitted in each translation unit that needs it, 
so it doesn't need to affect the library ABI.  These both seem like 
improvements to me.

More complicated is the question of the default violation handler: the 
lock3 implementation calls it "handle_contract_violation" in the global 
namespace, and overriding it is done with ELF symbol interposition, much 
like the replaceable allocation functions.  That approach seems 
reasonable, but I'd think we should use a reserved name, e.g. 
::__handle_contract_violation or __cxxabiv1::__contract_violation_handler.

The clang implementation above involves specifying the name of the 
handler on the compiler command line, which seems problematic, as it 
would tend to mean multiple independent violation handlers active at the 
same time.  Their default handler is std::terminate, which does avoid 
needing to add the default handler to the library.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
  2021-07-05 19:07                                 ` contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts) Jason Merrill
@ 2021-07-06 20:47                                   ` Jason Merrill
  2021-07-12 19:58                                   ` Jonathan Wakely
  1 sibling, 0 replies; 31+ messages in thread
From: Jason Merrill @ 2021-07-06 20:47 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches, Jeff Chapman, Andrew Sutton

On 7/5/21 3:07 PM, Jason Merrill wrote:
> On 6/26/21 10:23 AM, Andrew Sutton wrote:
>>
>> I ended up taking over this work from Jeff (CC'd on his existing email
>> address). I scraped all the contracts changes into one big patch
>> against master. See attached. The ChangeLog.contracts files list the
>> sum of changes for the patch, not the full history of the work.
> 
> Jonathan, can you advise where the library support should go?
> 
> In N4820 <contract> was part of the language-support clause, which makes 
> sense, but it uses string_view, which brings in a lot of the rest of the 
> library.  Did LWG talk about this when contracts went in?  How are 
> freestanding implementations expected to support contracts?
> 
> I imagine the header should be <experimental/contract> for now.
> 
> You've previously mentioned that various current experimental features 
> don't appear in libstdc++.so; that is not true of the current patch.
> 
> I see that https://github.com/arcosuc3m/clang-contracts takes the 
> approach, of teaching the compiler about std::contract_violation, 
> building up an object, and passing it to the handler directly, much like 
> we do for initializer_list.  Their equivalent of __on_contract_violation 
> is an internal function emitted in each translation unit that needs it, 
> so it doesn't need to affect the library ABI.  These both seem like 
> improvements to me.
> 
> More complicated is the question of the default violation handler: the 
> lock3 implementation calls it "handle_contract_violation" in the global 
> namespace, and overriding it is done with ELF symbol interposition, much 
> like the replaceable allocation functions.  That approach seems 
> reasonable, but I'd think we should use a reserved name, e.g. 
> ::__handle_contract_violation or __cxxabiv1::__contract_violation_handler.
> 
> The clang implementation above involves specifying the name of the 
> handler on the compiler command line, which seems problematic, as it 
> would tend to mean multiple independent violation handlers active at the 
> same time.  Their default handler is std::terminate, which does avoid 
> needing to add the default handler to the library.

I've pushed the patch with my adjustments so far to devel/c++-contracts 
on gcc.gnu.org.  One of those adjustments was changing the 
contract_violation data members to be const char *, to make creating an 
object easier, and making the member functions inline, to reduce the 
number of symbols added to the library.

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
  2021-07-05 19:07                                 ` contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts) Jason Merrill
  2021-07-06 20:47                                   ` Jason Merrill
@ 2021-07-12 19:58                                   ` Jonathan Wakely
  2021-07-14  3:56                                     ` Jason Merrill
  1 sibling, 1 reply; 31+ messages in thread
From: Jonathan Wakely @ 2021-07-12 19:58 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc Patches, Jeff Chapman, Andrew Sutton

On Mon, 5 Jul 2021 at 20:07, Jason Merrill <jason@redhat.com> wrote:
>
> On 6/26/21 10:23 AM, Andrew Sutton wrote:
> >
> > I ended up taking over this work from Jeff (CC'd on his existing email
> > address). I scraped all the contracts changes into one big patch
> > against master. See attached. The ChangeLog.contracts files list the
> > sum of changes for the patch, not the full history of the work.
>
> Jonathan, can you advise where the library support should go?
>
> In N4820 <contract> was part of the language-support clause, which makes
> sense, but it uses string_view, which brings in a lot of the rest of the
> library.  Did LWG talk about this when contracts went in?  How are
> freestanding implementations expected to support contracts?

I don't recall that being discussed, but I think I was in another room
for much of the contracts review.

If necessary we could make the std::char_traits<char> specialization
available freestanding, without the primary template (or the other
specializations). But since C++20 std::string_view also depends on
quite a lot of ranges, which depends on iterators, which is not
freestanding. Some of those dependencies were added more recently than
contracts was reviewed and then yanked out, so maybe wasn't considered
a big problem back then. In any case, depending on std::string_view
(even without the rest of std::basic_string_view) is not currently
possible for freestanding.

> I imagine the header should be <experimental/contract> for now.

Agreed.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
  2021-07-12 19:58                                   ` Jonathan Wakely
@ 2021-07-14  3:56                                     ` Jason Merrill
  2021-07-14 10:55                                       ` Jonathan Wakely
  0 siblings, 1 reply; 31+ messages in thread
From: Jason Merrill @ 2021-07-14  3:56 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc Patches, Jeff Chapman, Andrew Sutton

On 7/12/21 3:58 PM, Jonathan Wakely wrote:
> On Mon, 5 Jul 2021 at 20:07, Jason Merrill <jason@redhat.com> wrote:
>>
>> On 6/26/21 10:23 AM, Andrew Sutton wrote:
>>>
>>> I ended up taking over this work from Jeff (CC'd on his existing email
>>> address). I scraped all the contracts changes into one big patch
>>> against master. See attached. The ChangeLog.contracts files list the
>>> sum of changes for the patch, not the full history of the work.
>>
>> Jonathan, can you advise where the library support should go?
>>
>> In N4820 <contract> was part of the language-support clause, which makes
>> sense, but it uses string_view, which brings in a lot of the rest of the
>> library.  Did LWG talk about this when contracts went in?  How are
>> freestanding implementations expected to support contracts?
> 
> I don't recall that being discussed, but I think I was in another room
> for much of the contracts review.
> 
> If necessary we could make the std::char_traits<char> specialization
> available freestanding, without the primary template (or the other
> specializations). But since C++20 std::string_view also depends on
> quite a lot of ranges, which depends on iterators, which is not
> freestanding. Some of those dependencies were added more recently than
> contracts was reviewed and then yanked out, so maybe wasn't considered
> a big problem back then. In any case, depending on std::string_view
> (even without the rest of std::basic_string_view) is not currently
> possible for freestanding.

I guess I'll change string_view to const char* for now.

>> I imagine the header should be <experimental/contract> for now.
> 
> Agreed.

And the type std::experimental::??::contract_violation.  Maybe 
contracts_v1 for the inline namespace?

Did you have any thoughts about the violation handler?  Is it OK to add 
a default definition to the library, in the above namespace?

Jason


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
  2021-07-14  3:56                                     ` Jason Merrill
@ 2021-07-14 10:55                                       ` Jonathan Wakely
  2021-07-16 13:18                                         ` Andrew Sutton
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Wakely @ 2021-07-14 10:55 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc Patches, Jeff Chapman, Andrew Sutton

On Wed, 14 Jul 2021 at 04:56, Jason Merrill <jason@redhat.com> wrote:
>
> On 7/12/21 3:58 PM, Jonathan Wakely wrote:
> > On Mon, 5 Jul 2021 at 20:07, Jason Merrill <jason@redhat.com> wrote:
> >>
> >> On 6/26/21 10:23 AM, Andrew Sutton wrote:
> >>>
> >>> I ended up taking over this work from Jeff (CC'd on his existing email
> >>> address). I scraped all the contracts changes into one big patch
> >>> against master. See attached. The ChangeLog.contracts files list the
> >>> sum of changes for the patch, not the full history of the work.
> >>
> >> Jonathan, can you advise where the library support should go?
> >>
> >> In N4820 <contract> was part of the language-support clause, which makes
> >> sense, but it uses string_view, which brings in a lot of the rest of the
> >> library.  Did LWG talk about this when contracts went in?  How are
> >> freestanding implementations expected to support contracts?
> >
> > I don't recall that being discussed, but I think I was in another room
> > for much of the contracts review.
> >
> > If necessary we could make the std::char_traits<char> specialization
> > available freestanding, without the primary template (or the other
> > specializations). But since C++20 std::string_view also depends on
> > quite a lot of ranges, which depends on iterators, which is not
> > freestanding. Some of those dependencies were added more recently than
> > contracts was reviewed and then yanked out, so maybe wasn't considered
> > a big problem back then. In any case, depending on std::string_view
> > (even without the rest of std::basic_string_view) is not currently
> > possible for freestanding.
>
> I guess I'll change string_view to const char* for now.

I think that's best. Making std::string_view usable would take some work.

> >> I imagine the header should be <experimental/contract> for now.
> >
> > Agreed.
>
> And the type std::experimental::??::contract_violation.  Maybe
> contracts_v1 for the inline namespace?

LGTM

> Did you have any thoughts about the violation handler?  Is it OK to add
> a default definition to the library, in the above namespace?

I'd rather not have any std::experimental::* symbols go into the DSO.
For std::experimental::filesystem we added libstdc++fs.a, with no
corresponding .so library, which users need to link to explicitly to
use that TS. Would something like libstdc++contracts.a work here? Is
it just one symbol?

Aside: Ulrich Drepper suggested recently that the driver should have
been updated to automatically add -lstdc++fs so that using
<experimental/filesystem> was seamless, as the archive contents
wouldn't be used unless something in the program referred to the
symbols in it.

Is just using std::terminate as the handler viable? Or if we're sure
contracts in some form will go into the IS eventually, and the
signature won't change, we could just add it in __cxxabiv1:: as you
suggested earlier.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
  2021-07-14 10:55                                       ` Jonathan Wakely
@ 2021-07-16 13:18                                         ` Andrew Sutton
  0 siblings, 0 replies; 31+ messages in thread
From: Andrew Sutton @ 2021-07-16 13:18 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jason Merrill, gcc Patches, Jeff Chapman

> Is just using std::terminate as the handler viable? Or if we're sure
> contracts in some form will go into the IS eventually, and the
> signature won't change, we could just add it in __cxxabiv1:: as you
> suggested earlier.

No, the handler needs to be configurable (at least quietly) in order
to support experimentation by SG21. No idea if it will stay that way.

Andrew

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2021-07-16 13:19 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-13 19:23 [PATCH] implement pre-c++20 contracts Jeff Chapman
2019-12-10  5:58 ` Jason Merrill
2019-12-10  6:20   ` Jason Merrill
2020-03-24 14:23   ` Andrew Sutton
2020-05-07 15:56   ` Jeff Chapman
2020-07-10 17:53     ` Jeff Chapman
2020-07-28 12:52       ` Jeff Chapman
2020-12-02 20:33       ` Jason Merrill
2020-12-03 17:07         ` Andrew Sutton
2020-12-03 17:41           ` Jason Merrill
2020-12-04 13:35             ` Jeff Chapman
2021-01-04 14:58               ` [PATCH] PING " Jeff Chapman
2021-01-05 21:27                 ` Jason Merrill
2021-01-18 14:56                 ` Jason Merrill
2021-03-01 13:12                   ` Jeff Chapman
2021-03-26  2:53                     ` Jason Merrill
2021-04-30 17:44                       ` Jeff Chapman
2021-05-14 20:54                         ` Jason Merrill
2021-05-14 21:09                           ` Marek Polacek
2021-05-17 22:06                           ` Jason Merrill
2021-05-28 13:18                             ` Jeff Chapman
     [not found]                               ` <CAMJpcpX7zAbHr79sZefXRSn2bxFg+ei9YUzMoapShctq=TwgGQ@mail.gmail.com>
2021-07-01 15:14                                 ` Jason Merrill
2021-07-01 16:27                                   ` Andrew Sutton
2021-07-02 15:09                                     ` Jason Merrill
2021-07-02 15:30                                       ` Andrew Sutton
2021-07-05 19:07                                 ` contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts) Jason Merrill
2021-07-06 20:47                                   ` Jason Merrill
2021-07-12 19:58                                   ` Jonathan Wakely
2021-07-14  3:56                                     ` Jason Merrill
2021-07-14 10:55                                       ` Jonathan Wakely
2021-07-16 13:18                                         ` Andrew Sutton

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).