Skip to content

Commit 1b837a3

Browse files
Merge pull request gcc-mirror#93 from NinaRanns/const_param_check_fixes
fixing detection of non-const parameters in re-declarations
2 parents a0dfe96 + 2427236 commit 1b837a3

File tree

12 files changed

+558
-67
lines changed

12 files changed

+558
-67
lines changed

gcc/cp/contracts.cc

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2782,30 +2782,58 @@ constify_contract_access(tree decl)
27822782
return decl;
27832783
}
27842784

2785-
/* Do not allow non-const by-value params being used in postconditions. */
2785+
/* If declaration DECL is a PARM_DECL and it appears in a postcondition, then
2786+
check that it is not a non-const by-value param. LOCATION is where the
2787+
expression was found and is used for diagnostic purposes. */
27862788

2787-
bool
2788-
maybe_reject_param_in_postcondition (tree decl)
2789+
void
2790+
maybe_reject_param_in_postcondition (tree decl, location_t location)
27892791
{
27902792
if (flag_contracts_nonattr
2791-
&& !TREE_READONLY (decl)
27922793
&& TREE_CODE (decl) == PARM_DECL
27932794
&& should_constify_contract
27942795
&& processing_postcondition
2795-
&& !dependent_type_p (TREE_TYPE (decl))
2796-
&& !CP_TYPE_CONST_P (TREE_TYPE (decl))
27972796
&& !(REFERENCE_REF_P (decl)
27982797
&& TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL)
27992798
/* Return value parameter has DECL_ARTIFICIAL flag set. The flag
28002799
* presence of the flag should be sufficient to distinguish the
28012800
* return value parameter in this context. */
28022801
&& !(DECL_ARTIFICIAL (decl)))
28032802
{
2804-
error_at (DECL_SOURCE_LOCATION (decl),
2805-
"a value parameter used in a postcondition must be const");
2806-
return true;
2803+
set_parm_used_in_post (decl);
2804+
2805+
if (!CP_TYPE_CONST_P(TREE_TYPE (decl)) && !TREE_READONLY(decl))
2806+
{
2807+
error_at (location,
2808+
"a value parameter used in a postcondition must be const");
2809+
inform (DECL_SOURCE_LOCATION(decl), "parameter declared here");
2810+
}
2811+
}
2812+
}
2813+
2814+
/* Check if parameters used in postconditions are const qualified on
2815+
a redeclaration that does not specify contracts. */
2816+
2817+
void
2818+
check_param_in_redecl (tree olddecl, tree newdecl)
2819+
{
2820+
tree t1 = FUNCTION_FIRST_USER_PARM(olddecl);
2821+
tree t2 = FUNCTION_FIRST_USER_PARM(newdecl);
2822+
for (; t1 && t1 != void_list_node;
2823+
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
2824+
{
2825+
if (parm_used_in_post_p(t1))
2826+
{
2827+
set_parm_used_in_post (t2);
2828+
if (!CP_TYPE_CONST_P(TREE_TYPE (t2)) && !TREE_READONLY(t2))
2829+
{
2830+
error_at (DECL_SOURCE_LOCATION(t2),
2831+
"value parameter %qE used in a postcondition must be const", t2);
2832+
inform (DECL_SOURCE_LOCATION(olddecl),
2833+
"previous declaration here");
2834+
}
2835+
}
28072836
}
2808-
return false;
28092837
}
28102838

28112839
void
@@ -3277,8 +3305,9 @@ p2900_duplicate_contracts (tree newdecl, tree olddecl)
32773305

32783306
if (old_contracts && !new_contracts)
32793307
/* We allow re-declarations to omit contracts declared on the initial decl.
3280-
In fact, this is required if the conditions contain lambdas. */
3281-
;
3308+
In fact, this is required if the conditions contain lambdas. Check if
3309+
all the parameters are correctly const qualified. */
3310+
check_param_in_redecl (olddecl, newdecl);
32823311
else if (contract_any_deferred_p (new_contracts))
32833312
/* TODO: stash these and figure out how to process them later. */
32843313
;

gcc/cp/cp-tree.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
565565
DECL_SELF_REFERENCE_P (in a TYPE_DECL)
566566
DECL_INVALID_OVERRIDER_P (in a FUNCTION_DECL)
567567
DECL_UNINSTANIATED_TEMPLATE_FRIEND_P (in TEMPLATE_DECL)
568+
parm_used_in_post_p (in PARM_DECL)
568569
5: DECL_INTERFACE_KNOWN.
569570
6: DECL_THIS_STATIC (in VAR_DECL, FUNCTION_DECL or PARM_DECL)
570571
DECL_FIELD_IS_BASE (in FIELD_DECL)
@@ -8943,8 +8944,8 @@ extern tree grok_contract (tree, tree, tree, cp_expr, location_t);
89438944
extern tree finish_contract_condition (cp_expr);
89448945
extern void update_late_contract (tree, tree, cp_expr);
89458946
extern tree constify_contract_access (tree);
8946-
extern bool maybe_reject_param_in_postcondition (tree);
8947-
8947+
extern void maybe_reject_param_in_postcondition (tree, location_t);
8948+
extern void check_param_in_redecl (tree, tree);
89488949
extern tree view_as_const (tree);
89498950
extern tree maybe_contract_wrap_call (tree, tree);
89508951
extern bool emit_contract_wrapper_func (bool);
@@ -9025,6 +9026,24 @@ strip_contract_const_wrapper (tree exp)
90259026
return exp;
90269027
}
90279028

9029+
/* Indicate if PARM_DECL DECL is ODR used in a postcondition. */
9030+
9031+
inline void
9032+
set_parm_used_in_post (tree decl, bool constify = true)
9033+
{
9034+
gcc_checking_assert (TREE_CODE (decl) == PARM_DECL);
9035+
DECL_LANG_FLAG_4 (decl) = constify;
9036+
}
9037+
9038+
/* Test if PARM_DECL is ODR used in a postcondition. */
9039+
9040+
inline bool
9041+
parm_used_in_post_p (const_tree decl)
9042+
{
9043+
/* Check if this parameter is odr used within a function's postcondition */
9044+
return ((TREE_CODE (decl) == PARM_DECL) && DECL_LANG_FLAG_4 (decl));
9045+
}
9046+
90289047
/* Inline bodies. */
90299048

90309049
inline tree

gcc/cp/decl.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
22732273
declaration of the function or function template in the
22742274
translation unit." */
22752275
check_no_redeclaration_friend_default_args (olddecl, newdecl);
2276+
22762277
}
22772278
}
22782279
}

gcc/cp/pt.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22373,7 +22373,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
2237322373
/* force_paren_expr can also create a VIEW_CONVERT_EXPR. */
2237422374
RETURN (finish_parenthesized_expr (op));
2237522375

22376-
maybe_reject_param_in_postcondition (op);
22376+
maybe_reject_param_in_postcondition (op, EXPR_LOCATION (t));
2237722377

2237822378
if (flag_contracts_nonattr && should_constify_contract
2237922379
&& processing_contract_condition)

gcc/cp/search.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,8 @@ check_override_contracts (tree fndecl)
22732273
inform (DECL_SOURCE_LOCATION (basefn),
22742274
"overridden function is %qD", basefn);
22752275
}
2276+
2277+
check_param_in_redecl (basefn, fndecl);
22762278
}
22772279
}
22782280
}

gcc/cp/semantics.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5019,7 +5019,7 @@ finish_id_expression_1 (tree id_expression,
50195019
}
50205020
}
50215021

5022-
maybe_reject_param_in_postcondition (decl);
5022+
maybe_reject_param_in_postcondition (decl, location);
50235023
if (flag_contracts_nonattr && should_constify_contract
50245024
&& processing_contract_condition)
50255025
decl = constify_contract_access(decl);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// { dg-do compile }
2+
// { dg-options "-std=c++23 -fcontracts -fcontracts-nonattr -fcontracts-nonattr-inheritance-mode=P2900R13 " }
3+
4+
struct NTClass {
5+
//TODO, make non trivial when https://github.com/NinaRanns/gcc/issues/21 is solved
6+
// NTClass(){};
7+
// ~NTClass(){};
8+
};
9+
10+
template <typename... ARGS>
11+
bool check(ARGS... args){ return true;}
12+
13+
14+
struct Base
15+
{
16+
virtual void f (const NTClass i);
17+
18+
} ;
19+
20+
struct Derived : Base
21+
{
22+
virtual void f (const NTClass i) post (check (i));
23+
virtual void g (const NTClass i) pre ( check (i)) post (true);
24+
};
25+
26+
struct DerivedV : virtual Base
27+
{
28+
virtual void f (const NTClass i) post (check (i));
29+
virtual void g (const NTClass i) pre ( check (i)) post (true);
30+
};
31+
32+
void
33+
Derived::f (NTClass i){} // { dg-error "used in a postcondition must be const" }
34+
35+
void
36+
DerivedV::f (NTClass i){} // { dg-error "used in a postcondition must be const" }
37+
38+
void
39+
Derived::g (NTClass i){}
40+
41+
void
42+
DerivedV::g (NTClass i){}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// { dg-do compile }
2+
// { dg-options "-std=c++23 -fcontracts -fcontracts-nonattr -fcontracts-nonattr-inheritance-mode=P3653 " }
3+
4+
struct NTClass {
5+
//TODO, make non trivial when https://github.com/NinaRanns/gcc/issues/21 is solved
6+
// NTClass(){};
7+
// ~NTClass(){};
8+
};
9+
10+
template <typename... ARGS>
11+
bool check(ARGS... args){ return true;}
12+
13+
14+
struct Base
15+
{
16+
virtual void f (const NTClass i);
17+
18+
} ;
19+
20+
struct Derived : Base
21+
{
22+
virtual void f (const NTClass i) post (check (i));
23+
virtual void g (const NTClass i) pre ( check (i)) post (true);
24+
};
25+
26+
struct DerivedV : virtual Base
27+
{
28+
virtual void f (const NTClass i) post (check (i));
29+
virtual void g (const NTClass i) pre ( check (i)) post (true);
30+
};
31+
32+
void
33+
Derived::f (NTClass i){} // { dg-error "used in a postcondition must be const" }
34+
35+
void
36+
DerivedV::f (NTClass i){} // { dg-error "used in a postcondition must be const" }
37+
38+
void
39+
Derived::g (NTClass i){}
40+
41+
void
42+
DerivedV::g (NTClass i){}

0 commit comments

Comments
 (0)