Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/pending_changes/gh-514-c-mode-cv-qual-conv.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[GH #514]
C: pointer conversions adding qualifiers below the first level

In C, the front end accepted an implicit conversion between pointer types
that adds type qualifiers below the first level, such as "int **" to
"const int *const *", without a diagnostic. Such a conversion is valid in
C++, but in C the types pointed to are not compatible, so it violates a
constraint and requires a diagnostic (C23 6.5.17.2). A warning is now
issued; the conversion is still accepted. For example:

void f(int **p) {
const int *const *q;
q = p; // Now a warning.
}
6 changes: 5 additions & 1 deletion src/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -11682,11 +11682,15 @@ operators), 3.3.15 (?: operator), and 3.3.16.1 (simple assignment).
/* Allow conversion between pointers where type qualifiers are
being added at levels other than the first, e.g.,
"int **" -> "const int * const *". These are the const-safe
cases. This is an extension in C mode. */
cases. In C mode, this is an extension, and a diagnostic is
issued since the types pointed to are not "compatible". */
okay = TRUE;
std_conv->nontrivial_conversion = FALSE;
std_conv->type_qualifiers_added = qualifiers_added;
std_conv->warning_suggested = warning_suggested;
if (C_mode() && warning_suggested == ec_no_error) {
std_conv->warning_suggested = default_warning_code;
} /* if */
qualifiers_checked = TRUE;
} else if ((!suppress_extensions || any_cfront_mode()) &&
same_type_with_added_qualifiers(
Expand Down
1 change: 1 addition & 0 deletions tests/tests/regressions/.gh-514-cpp.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 --c++20 --strict Test_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 --c --c23 --strict Test_name.c
21 changes: 21 additions & 0 deletions tests/tests/regressions/.gh-514.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
fe_only -DTEST_NUMBER=1 --c --c23 --no_strict_gnu --gnu_version=130300 Test_name.c
"Test_name.c", line 16: warning: a value of type "int **" cannot be assigned to an entity of type "const int *const *"
q = p;
^

"Test_name.c", line 22: warning: a value of type "int **" cannot be used to initialize an entity of type "const int *const *"
const int *const *q = p;
^

"Test_name.c", line 29: warning: argument of type "int **" is incompatible with parameter of type "const int *const *"
take(p);
^

"Test_name.c", line 34: warning: return value type does not match the function type
return p;
^

"Test_name.c", line 39: warning: a value of type "int ***" cannot be used to initialize an entity of type "const int *const *const *"
const int *const *const *q = p;
^

21 changes: 21 additions & 0 deletions tests/tests/regressions/.gh-514.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
fe_only -DTEST_NUMBER=2 --c --c23 --strict_warnings Test_name.c
"Test_name.c", line 16: warning: a value of type "int **" cannot be assigned to an entity of type "const int *const *"
q = p;
^

"Test_name.c", line 22: warning: a value of type "int **" cannot be used to initialize an entity of type "const int *const *"
const int *const *q = p;
^

"Test_name.c", line 29: warning: argument of type "int **" is incompatible with parameter of type "const int *const *"
take(p);
^

"Test_name.c", line 34: warning: return value type does not match the function type
return p;
^

"Test_name.c", line 39: warning: a value of type "int ***" cannot be used to initialize an entity of type "const int *const *const *"
const int *const *const *q = p;
^

18 changes: 18 additions & 0 deletions tests/tests/regressions/gh-514-cpp.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//type:fp
//options_all:--c++20 --strict
//remark:C++: impl. ptr conv. w/ qualifiers below first level

// The const-safe conversions that need a diagnostic in C are standard
// qualification conversions in C++.

void take(const int *const *);
void take3(const int *const *const *);

void add_deep_const(int **p, int ***p3)
{
const int *const *q = p;

take(q);
take(p);
take3(p3);
}
17 changes: 17 additions & 0 deletions tests/tests/regressions/gh-514-positive.sft.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//type:fp
//options_all:--c --c23 --strict
//remark:C: impl. ptr conv. adding qualifiers at the first level only

void add_first_level_const(int **p)
{
int *const* q = p;

(void)q;
}

void explicit_deep_qualification(int **p)
{
const int *const* q = (const int *const* )p;

(void)q;
}
42 changes: 42 additions & 0 deletions tests/tests/regressions/gh-514.sft.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//type:fp
//options_all:--c --c23
//options:--no_strict_gnu --gnu_version=130300:--strict_warnings
//remark:C: impl. ptr conv. w/ qualifiers below first level

// C++ permits these conversions, but in C the types pointed to are not
// compatible, so each one requires a diagnostic.

void take(const int *const *);
void take3(const int *const *const *);

void assignment(int **p)
{
const int *const *q;

q = p;
take(q);
}

void initialization(int **p)
{
const int *const *q = p;

take(q);
}

void argument(int **p)
{
take(p);
}

const int *const *return_value(int **p)
{
return p;
}

void three_levels(int ***p)
{
const int *const *const *q = p;

take3(q);
}
Loading