Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mkString fixes (mostly moved from the multi-decl overhaul) #714

Merged
merged 8 commits into from
Oct 6, 2021
34 changes: 30 additions & 4 deletions clang/lib/3C/ConstraintVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,10 +833,34 @@ PointerVariableConstraint::mkString(Constraints &CS,
if (!ForItype && InferredGenericIndex == -1 && isVoidPtr())
K = Atom::A_Wild;

// In a case like `_Ptr<T> g[1]`, we need to push the ` g` onto EndStrs
// before we can push the `>` and start drilling into T.
//
// Exception: In a case like `int *g[1]`, we don't want an extra space after
// the `*` but we don't yet know whether we have a `*`, so we skip emitting
// the name. We have to also skip the addArrayAnnotations because it would
// cause the array annotations to be emitted before the name.
//
// Exception to the exception: In a case like `void (*fs[2])()`, we still
// want to avoid emitting the name (which would add an extra space after the
// `*`), but we _do_ need to call addArrayAnnotations so the array
// annotations end up with the variable name rather than after the function
// parameter list. The function pointer code knows to emit the name before
// EndStrs.
//
// This feels very ad-hoc but currently helps a number of the more complex
// regression tests and makes mkString correct in some additional cases in
// which 3C currently doesn't use it but might use it in the future. We hope
// to eventually overhaul this code
// (https://github.com/correctcomputation/checkedc-clang/issues/703).
if (PrevArr && ArrSizes.at(TypeIdx).first != O_SizedArray && !EmittedName) {
EmittedName = true;
addArrayAnnotations(ConstArrs, EndStrs);
EndStrs.push_front(" " + UseName);
if (K != Atom::A_Wild || FV != nullptr) {
addArrayAnnotations(ConstArrs, EndStrs);
}
if (K != Atom::A_Wild) {
EmittedName = true;
EndStrs.push_front(" " + UseName);
}
}
PrevArr = ArrSizes.at(TypeIdx).first == O_SizedArray;

Expand Down Expand Up @@ -926,6 +950,8 @@ PointerVariableConstraint::mkString(Constraints &CS,
// the the stack array type.
if (PrevArr && !EmittedName && AllArrays) {
EmittedName = true;
// Note: If the whole type is an array, we can't have a "*", so we don't
// need to worry about an extra space.
EndStrs.push_front(" " + UseName);
}

Expand Down Expand Up @@ -978,7 +1004,7 @@ PointerVariableConstraint::mkString(Constraints &CS,
Ss << Str;
}

if (IsReturn && !ForItype)
if (IsReturn && !ForItype && !StringRef(Ss.str()).endswith("*"))
Ss << " ";

return Ss.str();
Expand Down
2 changes: 1 addition & 1 deletion clang/test/3C/compound_literal.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void lists() {

int *d[2] = (int *[2]){&x, (int *)1};
//CHECK_NOALL: int *d[2] = (int *[2]){&x, (int *)1};
//CHECK_ALL: int * d _Checked[2] = (int * _Checked[2]){&x, (int *)1};
//CHECK_ALL: int *d _Checked[2] = (int * _Checked[2]){&x, (int *)1};
int *d0 = d[0];
//CHECK: int *d0 = d[0];

Expand Down
10 changes: 5 additions & 5 deletions clang/test/3C/fptr_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

void (*fs[2])(int *);
void (*f)(int *);
//CHECK_NOALL: void (* fs[2])(_Ptr<int>) = {((void *)0)};
//CHECK_NOALL: void (*fs[2])(_Ptr<int>) = {((void *)0)};
//CHECK_NOALL: void (*f)(_Ptr<int>) = ((void *)0);
//CHECK_ALL: _Ptr<void (_Ptr<int>)> fs _Checked[2] = {((void *)0)};
//CHECK_ALL: _Ptr<void (_Ptr<int>)> f = ((void *)0);

void (*gs[2])(int *);
void g_impl(int *x) { x = 1; }
void (*g)(int *) = g_impl;
//CHECK_NOALL: void (* gs[2])(int * : itype(_Ptr<int>)) = {((void *)0)};
//CHECK_NOALL: void (*gs[2])(int * : itype(_Ptr<int>)) = {((void *)0)};
//CHECK_NOALL: void g_impl(int *x : itype(_Ptr<int>)) { x = 1; }
//CHECK_NOALL: void (*g)(int * : itype(_Ptr<int>)) = g_impl;

Expand All @@ -30,21 +30,21 @@ void (*h)(void *);

int *(*is[2])(void);
int *(*i)(void);
//CHECK_NOALL: _Ptr<int> (* is[2])(void) = {((void *)0)};
//CHECK_NOALL: _Ptr<int> (*is[2])(void) = {((void *)0)};
//CHECK_NOALL: _Ptr<int> (*i)(void) = ((void *)0);
//CHECK_ALL: _Ptr<_Ptr<int> (void)> is _Checked[2] = {((void *)0)};
//CHECK_ALL: _Ptr<_Ptr<int> (void)> i = ((void *)0);

int *(**js[2])(void);
int *(**j)(void);
//CHECK_NOALL: _Ptr<int> (** js[2])(void) = {((void *)0)};
//CHECK_NOALL: _Ptr<int> (**js[2])(void) = {((void *)0)};
//CHECK_NOALL: _Ptr<int> (**j)(void) = ((void *)0);
//CHECK_ALL: _Ptr<_Ptr<_Ptr<int> (void)>> js _Checked[2] = {((void *)0)};
//CHECK_ALL: _Ptr<_Ptr<_Ptr<int> (void)>> j = ((void *)0);

int *(*ks[2][2])(void);
int *(*k)(void);
//CHECK_NOALL: _Ptr<int> (* ks[2][2])(void) = {((void *)0)};
//CHECK_NOALL: _Ptr<int> (*ks[2][2])(void) = {((void *)0)};
//CHECK_NOALL: _Ptr<int> (*k)(void) = ((void *)0);
//CHECK_ALL: _Ptr<_Ptr<int> (void)> ks _Checked[2] _Checked[2] = {((void *)0)};
//CHECK_ALL: _Ptr<_Ptr<int> (void)> k = ((void *)0);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/3C/itype_typedef.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void test2(td2 a) {
typedef int *td3;
td3 test3() {
//CHECK: typedef _Ptr<int> td3;
//CHECK: int * test3(void) : itype(td3) {
//CHECK: int *test3(void) : itype(td3) {
return (int*) 1;
}

Expand Down
10 changes: 2 additions & 8 deletions clang/test/3C/itypes_for_extern.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,8 @@ int *baz(int *a, int len, int *b) {
return a;
}

// FIXME: The space between after the first star is needed for the idempotence
// test to pass. If there isn't a space there, 3c will add one when
// re-run on its original output. This should be fixed ideally in two
// ways. First, the space shouldn't be added when not present in the
// original source, and second, the second conversion should not rewrite
// the declaration.
void buz(int * (*f)(int *, int *)) {}
//CHECK: void buz(int * ((*f)(int *, int *)) : itype(_Ptr<_Ptr<int> (_Ptr<int>, _Ptr<int>)>)) _Checked {}
void buz(int *(*f)(int *, int *)) {}
//CHECK: void buz(int *((*f)(int *, int *)) : itype(_Ptr<_Ptr<int> (_Ptr<int>, _Ptr<int>)>)) _Checked {}

typedef int * int_star;
void typedef_test(int_star p) {}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/3C/ptr_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void test1(int *a) {

int *b[1] = {a};
//CHECK_NOALL: int *b[1] = {a};
//CHECK_ALL: int * b _Checked[1] = {a};
//CHECK_ALL: int *b _Checked[1] = {a};
}

/* Example from from the issue */
Expand All @@ -40,7 +40,7 @@ int *foo() {
int z = 3;
int *ptrs[4] = {&x, &y, &z, (int *)5};
//CHECK_NOALL: int *ptrs[4] = {&x, &y, &z, (int *)5};
//CHECK_ALL: int * ptrs _Checked[4] = {&x, &y, &z, (int *)5};
//CHECK_ALL: int *ptrs _Checked[4] = {&x, &y, &z, (int *)5};
int *ret;
//CHECK: int *ret;
for (int i = 0; i < 4; i++) {
Expand Down