This is an archive of the discontinued LLVM Phabricator instance.

[Diagnostics] Check for misleading pointer declarations
AbandonedPublic

Authored by xbolva00 on Oct 2 2018, 10:34 AM.

Details

Reviewers
rsmith
Summary

void foo() {

char* a, b; // warn that b is not a pointer type as someone may expect

}

Fixes PR39150 (also I see a request for this checker on GCC Bugzilla)

Diff Detail

Event Timeline

xbolva00 created this revision.Oct 2 2018, 10:34 AM
xbolva00 updated this revision to Diff 167978.Oct 2 2018, 10:42 AM
  • Avoid possible crash

Thanks for working on this!

include/clang/Basic/DiagnosticSemaKinds.td
318–320

I think this should really be off by default, this is a stylistic warning that would be really noisy for existing projects. Also, I think the text might be better spelled as "declaring a variable of type %0; did you mean to declare a pointer?". Also, -Wmisleading-declarations doesn't really describe what this warning diagnoses. This is C, so there is plenty of ways to write a misleading declaration ;). Maybe -Wmisleading-pointer-declarator?

lib/Sema/SemaStmt.cpp
81

The null check here is redundant, new (Context) should never return nullptr.

xbolva00 updated this revision to Diff 167985.Oct 2 2018, 11:14 AM
  • Addressed review comments
xbolva00 retitled this revision from [Diagnostics] Check for misleading variable declarations to [Diagnostics] Check for misleading pointer declarations.Oct 2 2018, 11:16 AM

Any futher comments?

There's a false positive.

int **A, *B; // false positive: declaring a variable of type 'int *'; did you mean to declare a pointer?

And IMO this should also warn:

int **A, B; // no warning currently
xbolva00 added a comment.EditedOct 3 2018, 2:42 PM

Yes, I am gonna work on it after I finish other patch :)

rsmith added a comment.Oct 3 2018, 5:24 PM

I think we need some documented guidelines on what is and is not an appropriate warning for Clang. I think it's reasonable to warn in cases where we are confident that the code means something other than what the programmer or a later reader is likely to expect; it's less obvious to me whether this warning fits that categorization: while a lot of people are confused by C/C++'s multi-declarator declaration rules, there are also many people who are not, and who use this kind of coding pattern (if you look at, say, the ffmpeg source code, you can find all sorts of things like this: char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };, int *fds = NULL, fdsnum, fdsidx;, int *tmp, i, len;, int *p, vmax, v, n, i, j, k, code;, and so on).

Generally in the cases where we do accept such warnings on valid code that might nonetheless mean something different from what was intended, or be misread by people who have not internalized the relevant language rules, there is a simple syntactic workaround that suppresses the diagnostic, and we suggest that workaround in a note attached to the warning. (For example, for assignment in an if condition, we suggest adding another pair of parentheses, and likewise we suggest adding parentheses for an && expression as an operand of an || expression.) Is there a similar syntactic workaround we can suggest here? For example, would

int *ptr, (a), b, c;

... suppress the warning for a?

rsmith added a comment.Oct 3 2018, 5:27 PM
int *ptr, (a), b, c;

Another possible heuristic for suppressing the check: only warn if there is whitespace before the identifier. So:

int* a, b; // warning
int *a, b; // no warning
lib/Sema/SemaStmt.cpp
82–95

This is an inappropriate way of performing the check. Instead, you should look at the syntactic form of the declarator while parsing it.

void test(void) {

int *a;
int* b;

}

TranslationUnitDecl
`-FunctionDecl <line:4:1, line:7:1> line:4:6 test 'void ()'

`-CompoundStmt <col:17, line:7:1>
  |-DeclStmt <line:5:5, col:11>
  | `-VarDecl <col:5, col:10> col:10 a 'int *'
  `-DeclStmt <line:6:5, col:11>
    `-VarDecl <col:5, col:10> col:10 b 'int *'

Why not 'int*' in ast dump?

xbolva00 abandoned this revision.Oct 6 2018, 9:02 AM

This shouldn't be implemented here, better choice is clang-tidy. Closing this revision.