Skip to content

Commit 0fdd9c9

Browse files
Merge pull request gcc-mirror#85 from NinaRanns/contracts_return_value_const
addressing return value constness
2 parents 11f4a27 + a5a7368 commit 0fdd9c9

File tree

5 files changed

+107
-16
lines changed

5 files changed

+107
-16
lines changed

gcc/cp/contracts.cc

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -613,10 +613,6 @@ make_postcondition_variable (cp_expr id, tree type)
613613
DECL_ARTIFICIAL (decl) = true;
614614
DECL_SOURCE_LOCATION (decl) = id.get_location ();
615615

616-
/* Maybe constify the postcondition variable. */
617-
if (flag_contracts_nonattr && should_constify_contract)
618-
TREE_READONLY(decl) = true;
619-
620616
pushdecl (decl);
621617
return decl;
622618
}
@@ -2734,10 +2730,15 @@ finish_contract_condition (cp_expr condition)
27342730

27352731
tree view_as_const(tree decl)
27362732
{
2737-
tree ctype = TREE_TYPE (decl);
2738-
ctype = cp_build_qualified_type (ctype, (cp_type_quals (ctype)
2739-
| TYPE_QUAL_CONST));
2740-
decl = build1 (VIEW_CONVERT_EXPR, ctype, decl);
2733+
if (!contract_const_wrapper_p (decl))
2734+
{
2735+
tree ctype = TREE_TYPE (decl);
2736+
ctype = cp_build_qualified_type (ctype, (cp_type_quals (ctype)
2737+
| TYPE_QUAL_CONST));
2738+
decl = build1 (VIEW_CONVERT_EXPR, ctype, decl);
2739+
/* Mark the VCE as contract const wrapper. */
2740+
decl->base.private_flag = true;
2741+
}
27412742
return decl;
27422743
}
27432744

@@ -2746,14 +2747,9 @@ tree view_as_const(tree decl)
27462747
tree
27472748
constify_contract_access(tree decl)
27482749
{
2749-
/* only constifies the automatic storage variables for now.
2750-
* The postcondition variable is created const. Parameters need to be
2751-
* checked separately, and we also need to make references and *this const
2752-
*/
27532750

2754-
/* We check if we have a variable of automatic storage duration, a parameter,
2755-
* a variable of automatic storage duration of reference type, or a
2756-
* parameter of reference type
2751+
/* We check if we have a variable, a parameter, a variable of reference type,
2752+
* or a parameter of reference type
27572753
*/
27582754
if (!TREE_READONLY (decl)
27592755
&& (VAR_P (decl)
@@ -2783,7 +2779,11 @@ maybe_reject_param_in_postcondition (tree decl)
27832779
&& !dependent_type_p (TREE_TYPE (decl))
27842780
&& !CP_TYPE_CONST_P (TREE_TYPE (decl))
27852781
&& !(REFERENCE_REF_P (decl)
2786-
&& TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL))
2782+
&& TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL)
2783+
/* Return value parameter has DECL_ARTIFICIAL flag set. The flag
2784+
* presence of the flag should be sufficient to distinguish the
2785+
* return value parameter in this context. */
2786+
&& !(DECL_ARTIFICIAL (decl)))
27872787
{
27882788
error_at (DECL_SOURCE_LOCATION (decl),
27892789
"a value parameter used in a postcondition must be const");

gcc/cp/cp-tree.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9001,6 +9001,29 @@ set_contract_const (tree t, bool constify)
90019001
TREE_LANG_FLAG_4 (CONTRACT_CHECK (t)) = constify;
90029002
}
90039003

9004+
/* Test if EXP is a contract const wrapper node. */
9005+
9006+
inline bool
9007+
contract_const_wrapper_p (const_tree exp)
9008+
{
9009+
/* A wrapper node has code VIEW_CONVERT_EXPR, and the flag base.private_flag
9010+
is set. The wrapper node is used to Used to constify entities inside
9011+
contract assertions. */
9012+
return ((TREE_CODE (exp) == VIEW_CONVERT_EXPR) && exp->base.private_flag);
9013+
}
9014+
9015+
/* If EXP is a contract_const_wrapper_p, return the wrapped expression.
9016+
Otherwise, do nothing. */
9017+
9018+
inline tree
9019+
strip_contract_const_wrapper (tree exp)
9020+
{
9021+
if (contract_const_wrapper_p (exp))
9022+
return TREE_OPERAND (exp, 0);
9023+
else
9024+
return exp;
9025+
}
9026+
90049027
/* Inline bodies. */
90059028

90069029
inline tree

gcc/cp/semantics.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12593,6 +12593,12 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
1259312593
if (identifier_p (expr))
1259412594
expr = lookup_name (expr);
1259512595

12596+
/* If e is a constified expression inside a contract assertion,
12597+
strip the const wrapper. Per P2900R14, "For a function f with the
12598+
return type T , the result name is an lvalue of type const T , decltype(r)
12599+
is T , and decltype((r)) is const T&." */
12600+
expr = strip_contract_const_wrapper (expr);
12601+
1259612602
if (INDIRECT_REF_P (expr)
1259712603
|| TREE_CODE (expr) == VIEW_CONVERT_EXPR)
1259812604
/* This can happen when the expression is, e.g., "a.b". Just
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// check that the return value has correct const qualification
2+
// { dg-do run }
3+
// { dg-options "-std=c++2b -fcontracts -fcontracts-nonattr " }
4+
5+
6+
#include <type_traits>
7+
8+
bool is_constified(int &){ return false;}
9+
10+
bool is_constified(const int &){ return true;}
11+
12+
13+
int f1(int i)
14+
pre (is_constified(i))
15+
pre (std::is_same<decltype(i), int>::value)
16+
pre (std::is_same<decltype((i)), const int&>::value)
17+
18+
post (r: is_constified(r))
19+
post (r: std::is_same<decltype(r), int>::value)
20+
post (r: std::is_same<decltype((r)), const int&>::value)
21+
{ return i; };
22+
23+
int& f2(int& i)
24+
pre (is_constified(i))
25+
pre (std::is_same<decltype(i), int&>::value)
26+
pre (std::is_same<decltype((i)), const int&>::value)
27+
28+
post (r: is_constified(r))
29+
post (r: std::is_same<decltype(r), int&>::value)
30+
post (r: std::is_same<decltype((r)), const int&>::value)
31+
{
32+
static_assert(std::is_same<decltype(i), int&>::value);
33+
return i;
34+
}
35+
36+
int* f2(int* i)
37+
pre (std::is_same<decltype(i), int*>::value)
38+
pre (std::is_same<decltype((i)),int * const>::value)
39+
40+
post (r: std::is_same<decltype(r), int *>::value)
41+
post (r: std::is_same<decltype((r)),int * const>::value)
42+
{ return i;}
43+
44+
int const * f2(int const * i)
45+
pre (std::is_same<decltype(i), int const *>::value)
46+
pre (std::is_same<decltype((i)),int const * const>::value)
47+
48+
post (r: std::is_same<decltype(r), int const *>::value)
49+
post (r: std::is_same<decltype((r)),int const * const>::value)
50+
{ return i;}
51+
52+
int main()
53+
{
54+
55+
int i = 4;
56+
f1(i);
57+
f2(i);
58+
59+
}

gcc/tree-core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,9 @@ struct GTY(()) tree_base {
13641364
ENUM_IS_OPAQUE in
13651365
ENUMERAL_TYPE
13661366
1367+
contract_const_wrapper_p in
1368+
VIEW_CONVERT_EXPR
1369+
13671370
protected_flag:
13681371
13691372
TREE_PROTECTED in

0 commit comments

Comments
 (0)