From: Jason Merrill Date: Fri, 28 Oct 2022 15:37:23 +0000 (-0400) Subject: c++: move duplicate_contracts to contracts.cc X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5080aec5f3f0eae334883c099f93070e6c3a5b64;p=thirdparty%2Fgcc.git c++: move duplicate_contracts to contracts.cc gcc/cp/ChangeLog: * cp-tree.h (duplicate_contracts): Add prototype. * contracts.cc (duplicate_contracts): Move from... * decl.cc (duplicate_contracts): ...here. * parser.cc (cp_parser_contract_attribute_spec): Fix typo. --- diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index 214be7c671f1..272448d07d83 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -2087,4 +2087,105 @@ apply_postcondition_to_return (tree expr) return call; } +/* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of + guarded functions. Note that attributes on new friend declarations have not + been processed yet, so we take those from the global above. */ + +void +duplicate_contracts (tree newdecl, tree olddecl) +{ + /* Compare contracts to see if they match. */ + tree old_contracts = DECL_CONTRACTS (olddecl); + tree new_contracts = DECL_CONTRACTS (newdecl); + + if (!old_contracts && !new_contracts) + return; + + location_t old_loc = DECL_SOURCE_LOCATION (olddecl); + location_t new_loc = DECL_SOURCE_LOCATION (newdecl); + + /* If both declarations specify contracts, ensure they match. + + TODO: This handles a potential error a little oddly. Consider: + + struct B { + virtual void f(int n) [[pre: n == 0]]; + }; + struct D : B { + void f(int n) override; // inherits contracts + }; + void D::f(int n) [[pre: n == 0]] // OK + { } + + It's okay because we're explicitly restating the inherited contract. + Changing the precondition on the definition D::f causes match_contracts + to complain about the mismatch. + + This would previously have been diagnosed as adding contracts to an + override, but this seems like it should be well-formed. */ + if (old_contracts && new_contracts) + { + if (!match_contract_conditions (old_loc, old_contracts, + new_loc, new_contracts, + cmc_declaration)) + return; + } + + /* Handle cases where contracts are omitted in one or the other + declaration. */ + if (old_contracts) + { + /* Contracts have been previously specified by are no omitted. The + new declaration inherits the existing contracts. */ + if (!new_contracts) + copy_contract_attributes (newdecl, olddecl); + + /* In all cases, remove existing contracts from OLDDECL to prevent the + attribute merging function from adding excess contracts. */ + remove_contract_attributes (olddecl); + } + else if (!old_contracts) + { + /* We are adding contracts to a declaration. */ + if (new_contracts) + { + /* We can't add to a previously defined function. */ + if (DECL_INITIAL (olddecl)) + { + auto_diagnostic_group d; + error_at (new_loc, "cannot add contracts after definition"); + inform (DECL_SOURCE_LOCATION (olddecl), "original definition here"); + return; + } + + /* We can't add to an unguarded virtual function declaration. */ + if (DECL_VIRTUAL_P (olddecl) && new_contracts) + { + auto_diagnostic_group d; + error_at (new_loc, "cannot add contracts to a virtual function"); + inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here"); + return; + } + + /* Depending on the "first declaration" rule, we may not be able + to add contracts to a function after the fact. */ + if (flag_contract_strict_declarations) + { + warning_at (new_loc, + OPT_fcontract_strict_declarations_, + "declaration adds contracts to %q#D", + olddecl); + return; + } + + /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to + remap them because NEWDECL's parameters will replace those of + OLDDECL. Remove the contracts from NEWDECL so they aren't + cloned when merging. */ + copy_contract_attributes (olddecl, newdecl); + remove_contract_attributes (newdecl); + } + } +} + #include "gt-cp-contracts.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 11ac082c89f4..a212aa2659d4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7788,6 +7788,7 @@ extern void maybe_update_postconditions (tree); extern void start_function_contracts (tree); extern void finish_function_contracts (tree); extern tree apply_postcondition_to_return (tree); +extern void duplicate_contracts (tree, tree); inline void set_decl_contracts (tree decl, tree contract_attrs) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 9740129456b0..d6eb50a260bb 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -1475,107 +1475,6 @@ duplicate_function_template_decls (tree newdecl, tree olddecl) return false; } -/* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of - guarded functions. Note that attributes on new friend declarations have not - been processed yet, so we take those from the global above. */ - -static void -duplicate_contracts (tree newdecl, tree olddecl) -{ - /* Compare contracts to see if they match. */ - tree old_contracts = DECL_CONTRACTS (olddecl); - tree new_contracts = DECL_CONTRACTS (newdecl); - - if (!old_contracts && !new_contracts) - return; - - location_t old_loc = DECL_SOURCE_LOCATION (olddecl); - location_t new_loc = DECL_SOURCE_LOCATION (newdecl); - - /* If both declarations specify contracts, ensure they match. - - TODO: This handles a potential error a little oddly. Consider: - - struct B { - virtual void f(int n) [[pre: n == 0]]; - }; - struct D : B { - void f(int n) override; // inherits contracts - }; - void D::f(int n) [[pre: n == 0]] // OK - { } - - It's okay because we're explicitly restating the inherited contract. - Changing the precondition on the definition D::f causes match_contracts - to complain about the mismatch. - - This would previously have been diagnosed as adding contracts to an - override, but this seems like it should be well-formed. */ - if (old_contracts && new_contracts) - { - if (!match_contract_conditions (old_loc, old_contracts, - new_loc, new_contracts, - cmc_declaration)) - return; - } - - /* Handle cases where contracts are omitted in one or the other - declaration. */ - if (old_contracts) - { - /* Contracts have been previously specified by are no omitted. The - new declaration inherits the existing contracts. */ - if (!new_contracts) - copy_contract_attributes (newdecl, olddecl); - - /* In all cases, remove existing contracts from OLDDECL to prevent the - attribute merging function from adding excess contracts. */ - remove_contract_attributes (olddecl); - } - else if (!old_contracts) - { - /* We are adding contracts to a declaration. */ - if (new_contracts) - { - /* We can't add to a previously defined function. */ - if (DECL_INITIAL (olddecl)) - { - auto_diagnostic_group d; - error_at (new_loc, "cannot add contracts after definition"); - inform (DECL_SOURCE_LOCATION (olddecl), "original definition here"); - return; - } - - /* We can't add to an unguarded virtual function declaration. */ - if (DECL_VIRTUAL_P (olddecl) && new_contracts) - { - auto_diagnostic_group d; - error_at (new_loc, "cannot add contracts to a virtual function"); - inform (DECL_SOURCE_LOCATION (olddecl), "original declaration here"); - return; - } - - /* Depending on the "first declaration" rule, we may not be able - to add contracts to a function after the fact. */ - if (flag_contract_strict_declarations) - { - warning_at (new_loc, - OPT_fcontract_strict_declarations_, - "declaration adds contracts to %q#D", - olddecl); - return; - } - - /* Copy the contracts from NEWDECL to OLDDECL. We shouldn't need to - remap them because NEWDECL's parameters will replace those of - OLDDECL. Remove the contracts from NEWDECL so they aren't - cloned when merging. */ - copy_contract_attributes (olddecl, newdecl); - remove_contract_attributes (newdecl); - } - } -} - /* OLD_PARMS is the innermost set of template parameters for some template declaration, and NEW_PARMS is the corresponding set of template parameters for a redeclaration of that template. Merge the default arguments within diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 7399c2f8a368..a911a660178f 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -29688,7 +29688,7 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute) DEFPARSE_TOKENS (condition) = cp_token_cache_new (first, last); DEFPARSE_INSTANTIATIONS (condition) = NULL; - /* And it's corresponding contract. */ + /* And its corresponding contract. */ contract = grok_contract (attribute, mode, identifier, condition, loc); } else