Skip to content

Commit

Permalink
C front-end: refuse duplicate declaration of local variable
Browse files Browse the repository at this point in the history
Just like GCC, Clang, or Visual Studio we should reject duplicate
declarations of local variables in the same scope.

Fixes: #8129
  • Loading branch information
tautschnig committed Jan 23, 2024
1 parent 79fafbe commit 6728195
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 41 deletions.
15 changes: 15 additions & 0 deletions regression/ansi-c/duplicate_local1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// duplicate globals are accepted by compilers
int x;
int x;

int main()
{
int a = 10;

// gcc: error: redeclaration of 'a' with no linkage
int a;

a++;

return 0;
}
9 changes: 9 additions & 0 deletions regression/ansi-c/duplicate_local1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
main.c

redeclaration of 'main::1::a' with no linkage$
CONVERSION ERROR
^EXIT=(1|64)$
^SIGNAL=0$
--
redeclaration of 'x' with no linkage$
20 changes: 10 additions & 10 deletions regression/cbmc-shadow-memory/nondet-size-arrays1/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ int main()
assert(__CPROVER_get_field(z + 4, "field1") == 15);
assert(__CPROVER_get_field(z + 4, "field2") == 16);

int i;
__CPROVER_assume(0 <= i && i < n);
__CPROVER_set_field(&(B[i]), "field1", 42);
assert(__CPROVER_get_field(&(B[i]), "field1") == 42);
int j;
__CPROVER_assume(0 <= j && j < n);
__CPROVER_set_field(&(B[j]), "field1", 42);
assert(__CPROVER_get_field(&(B[j]), "field1") == 42);

z = &(B[i]);
z = &(B[j]);
__CPROVER_set_field(z, "field1", 43);
assert(__CPROVER_get_field(z, "field1") == 43);

Expand All @@ -101,12 +101,12 @@ int main()
assert(__CPROVER_get_field(z + 4, "field1") == 15);
assert(__CPROVER_get_field(z + 4, "field2") == 16);

int i;
__CPROVER_assume(0 <= i && i < n);
__CPROVER_set_field(&(C[i]), "field1", 42);
assert(__CPROVER_get_field(&(C[i]), "field1") == 42);
int l;
__CPROVER_assume(0 <= l && l < n);
__CPROVER_set_field(&(C[l]), "field1", 42);
assert(__CPROVER_get_field(&(C[l]), "field1") == 42);

z = &(C[i]);
z = &(C[l]);
__CPROVER_set_field(z, "field1", 43);
assert(__CPROVER_get_field(z, "field1") == 43);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ void main()
struct test_struct value;

// Simplify a pointer inside a struct
int symbol;
value.pointer_component = &symbol;

// Simplify
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ int main()
assert(pa == &(y.a));
assert(pa != &(y.a));

int *pb = &(x.b);
assert(pb == &(y.a));
assert(pb != &(y.a));
int *pc = &(x.b);
assert(pc == &(y.a));
assert(pc != &(y.a));
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ main.c
^\[main.assertion.4\] .* assertion pb != &\(x.a\): SUCCESS
^\[main.assertion.5\] .* assertion pa == &\(y.a\): FAILURE
^\[main.assertion.6\] .* assertion pa != &\(y.a\): SUCCESS
^\[main.assertion.7\] .* assertion pb == &\(y.a\): FAILURE
^\[main.assertion.8\] .* assertion pb != &\(y.a\): SUCCESS
^\[main.assertion.7\] .* assertion pc == &\(y.a\): FAILURE
^\[main.assertion.8\] .* assertion pc != &\(y.a\): SUCCESS
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ main.c
^\[main.assertion.4\] .* assertion pb != &\(x.a\): UNKNOWN
^\[main.assertion.5\] .* assertion pa == &\(y.a\): UNKNOWN
^\[main.assertion.6\] .* assertion pa != &\(y.a\): UNKNOWN
^\[main.assertion.7\] .* assertion pb == &\(y.a\): UNKNOWN
^\[main.assertion.8\] .* assertion pb != &\(y.a\): UNKNOWN
^\[main.assertion.7\] .* assertion pc == &\(y.a\): UNKNOWN
^\[main.assertion.8\] .* assertion pc != &\(y.a\): UNKNOWN
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ main.c
^\[main.assertion.4\] .* assertion pb != &\(x.a\): SUCCESS
^\[main.assertion.5\] .* assertion pa == &\(y.a\): FAILURE
^\[main.assertion.6\] .* assertion pa != &\(y.a\): SUCCESS
^\[main.assertion.7\] .* assertion pb == &\(y.a\): FAILURE
^\[main.assertion.8\] .* assertion pb != &\(y.a\): SUCCESS
^\[main.assertion.7\] .* assertion pc == &\(y.a\): FAILURE
^\[main.assertion.8\] .* assertion pc != &\(y.a\): SUCCESS
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,16 @@ int main()
int x = 4;
int y = 5;
int *ps[2] = {&x, &y};
int i;
int l;
if(nondet > 2)
{
i = 0;
l = 0;
}
else
{
i = 1;
l = 1;
}
*(ps[i]) = 4;
*(ps[l]) = 4;

__CPROVER_assert(*ps[0] == 4, "*ps[0]==4");
__CPROVER_assert(*ps[1] == 4, "*ps[1]==4");
Expand Down
12 changes: 12 additions & 0 deletions src/ansi-c/c_typecheck_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,19 @@ void c_typecheck_baset::typecheck_symbol(symbolt &symbol)
if(symbol.is_type)
typecheck_redefinition_type(existing_symbol, symbol);
else
{
if(
(!old_it->second.is_static_lifetime || !symbol.is_static_lifetime) &&
symbol.type.id() != ID_code)
{
error().source_location = symbol.location;
error() << "redeclaration of '" << symbol.display_name()
<< "' with no linkage" << eom;
throw 0;
}

typecheck_redefinition_non_type(existing_symbol, symbol);
}
}
}

Expand Down
46 changes: 29 additions & 17 deletions unit/compound_block_locations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,11 @@ SCENARIO("Compound blocks should have a location")
"/* 4 */ { \n"
"/* 5 */ int x; \n"
"/* 6 */ if(x) \n"
"/* 7 */ int x = 1; \n"
"/* 8 */ } \n"
"/* 9 */ } \n",
"/* 7 */ { \n"
"/* 8 */ int x = 1; \n"
"/* 9 */ } \n"
"/* 10 */ } \n"
"/* 11 */ } \n",
{{ID_while, 3}, {ID_ifthenelse, 6}});

checker.check(
Expand Down Expand Up @@ -233,21 +235,31 @@ SCENARIO("Compound blocks should have a location")
"/* 4 */ switch(x) \n"
"/* 5 */ { \n"
"/* 6 */ case 1: \n"
"/* 7 */ int y = 1; \n"
"/* 8 */ break; \n"
"/* 9 */ case 2: \n"
"/* 10 */ int y = 2; \n"
"/* 11 */ int z = 2; \n"
"/* 12 */ break; \n"
"/* 13 */ case 3: \n"
"/* 14 */ int y = 3; \n"
"/* 15 */ case 4: \n"
"/* 16 */ int y = 4; \n"
"/* 17 */ break; \n"
"/* 18 */ default: \n"
"/* 19 */ int y = 5; \n"
"/* 7 */ { \n"
"/* 8 */ int y = 1; \n"
"/* 9 */ break; \n"
"/* 10 */ } \n"
"/* 11 */ case 2: \n"
"/* 12 */ { \n"
"/* 13 */ int y = 2; \n"
"/* 14 */ int z = 2; \n"
"/* 15 */ break; \n"
"/* 16 */ } \n"
"/* 17 */ case 3: \n"
"/* 18 */ { \n"
"/* 19 */ int y = 3; \n"
"/* 20 */ } \n"
"/* 21 */ } \n",
"/* 21 */ case 4: \n"
"/* 22 */ { \n"
"/* 23 */ int y = 4; \n"
"/* 24 */ break; \n"
"/* 25 */ } \n"
"/* 26 */ default: \n"
"/* 27 */ { \n"
"/* 28 */ int y = 5; \n"
"/* 29 */ } \n"
"/* 30 */ } \n"
"/* 31 */ } \n",
{{ID_switch, 6}});
}

Expand Down

0 comments on commit 6728195

Please sign in to comment.