This is an archive of the discontinued LLVM Phabricator instance.

[clang-tidy] Introduce fuchsia-global-variables check
Needs ReviewPublic

Authored by Caslyn on Jun 14 2023, 1:21 PM.

Details

Summary

Introduce a clang-tidy check to the fuchsia module to warn of any static
or global variables that do not have trivial destructors.

The implementation is a pared down version of the Google3
check with configurable options to add types for the check to ignore
(e.g. LazyRE2).

Diff Detail

Event Timeline

Caslyn created this revision.Jun 14 2023, 1:21 PM
Caslyn updated this revision to Diff 531489.Jun 14 2023, 1:35 PM

Fixes, cleanups.

Caslyn updated this revision to Diff 531932.Jun 15 2023, 4:02 PM

Include exception for variables declared in macros; cleanups.

Caslyn updated this revision to Diff 532713.Jun 19 2023, 10:54 AM

Add constinit exception, remove G3 exceptions

Caslyn published this revision for review.Jun 20 2023, 11:03 AM
Caslyn added reviewers: ymandel, Prabhuk.
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptJun 20 2023, 11:04 AM
PiotrZSL requested changes to this revision.Jun 20 2023, 1:26 PM

This check overlap with fuchsia-statically-constructed-objects.
In fact only new warnings are in lines 118, 111, 99.

Provided link is dead.
Fuchsia codding standard does not forbid global objects with non-trivial destructors: https://fuchsia.dev/fuchsia-src/development/languages/c-cpp/cxx?hl=en

Looks like what you trying to implement is an google style rule: "https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables" -> "Objects with static storage duration are forbidden unless they are trivially destructible. "
Therefor this check should be in google namespace, not fuchsia.
Please also look into: https://github.com/llvm/llvm-project/issues/62334

Personally I would see this as some generic misc-non-trivial-global-variable that could handle both initialization & destruction, and simply some standards could alias it.

clang-tools-extra/clang-tidy/fuchsia/GlobalVariablesCheck.cpp
31

may not work with typedefs to reference

32–33

there can be some implicitCasts here, and it wont match, also CXXBindTemporaryExpr can show up, this isn't a good way...

39

what about typedefs ?

47

TK_AsIs is default.

87–88

do not use unless, because other checks make set other rules, and we could run into conflict between them

97

if you put non trivial type into std::array, then std::array instance will become non-trivial itself, no need to look into arguments.

clang-tools-extra/docs/clang-tidy/checks/fuchsia/global-variables.rst
29

wrong example, using = default will make it trivial, put something into destructor.

40

would be nice to point out to a rule, that it implements.

This revision now requires changes to proceed.Jun 20 2023, 1:26 PM
Caslyn updated this revision to Diff 533832.Jun 22 2023, 5:28 PM
Caslyn marked 4 inline comments as done.

Fixes from review.

Thanks for the review @PiotrZSL, I’m new to this space and appreciate the comments. I have a few questions around some of them and would greatly appreciate any guidance you can give.

The intent of this patch is to upstream a generic version of the google style check (apologies for the private link) for use on Fuchsia and other projects. I’m happy to make this check a misc check that handles initialization and destruction if you wouldn’t mind advising a little bit. To handle the initialization aspect, would you suggest I combine logic from the existing fuchsia-statically-constructed-objects check?

Please also look into: https://github.com/llvm/llvm-project/issues/62334

I see there’s some potential clean up for the fuchsia module. I can take a stab at that ticket after this patch.

clang-tools-extra/clang-tidy/fuchsia/GlobalVariablesCheck.cpp
32–33

Is there a better way to implement this intent while handling those corner cases?

39

There is the typedef scenario tested on L#90 the global-variables.cpp test and I've added an additional test for typedef to references - are there any other test cases I can add to make sure this check handles them correctly?

97

Done - removed special handling for std::array.

PiotrZSL added inline comments.Jun 22 2023, 10:25 PM
clang-tools-extra/clang-tidy/fuchsia/GlobalVariablesCheck.cpp
27

Check LLVM codding standard, use CammelCase, and put it into matcher bellow anyway.

31

you can easily use here hasType(qualType(hasCanonicalType(references, it would work with typedefs to references.

32–33

in fact only thing that you need to check is if lifetime of materializeTemporaryExpr is extended by this varDecl, probably using getExtendingDecl () or getStroageDuration would be sufficient.

35

i would expect that this check would utilize CXXRecordDecl::hasNonTrivialDestructor().

36

only classes can be non trivial to destroy, so we should exclude on this level all types that are not CXXRecordDecl.

37

could be better, like in other checks.

37
39

typedef for const reference of non trivial type that is used to exend lfietime of variable (calling function that returns object with non trivial destructor).

clang-tools-extra/docs/clang-tidy/checks/fuchsia/global-variables.rst
4

I would name this check as: misc-no-static-variable-non-trivial-dtor or something similar, and then google check would just alias it as google-global-variables or something, and then fuchsia check could be named misc-no-static-variable-non-trivial-ctor, and current check could alias it. My main reason for that is very often awkward to use google check in project for something common, like for example explicit constructors. Those 2 rules I consider +- common, not all project need them but some project that code for DSP for example could find them useful.

You can do renaming at the end, there is script for that in repository.

38–39

obsolete

clang-tools-extra/test/clang-tidy/checkers/fuchsia/global-variables.cpp
8

Note: Remove all constructors from those classes here, we should teat this check on classes that are trivial to construct, but non trival to destroy.

36
104

that will act just like alias
``NonTriviallyDestructibleClass XYZ;
typedef_ref_ntdc = XYZ;``
this `new` here is confusing... both examples should be made simpler.

164

what about global object in a template function:
``
template<typename T> const T& fun() {

static T value;
return value;

}
``
and then calling this function with both non trivial and trivial to destroy type.

Caslyn updated this revision to Diff 535546.Jun 28 2023, 3:06 PM
Caslyn marked 12 inline comments as done.

Changes per review.

Hi Piotr - I'm sorry for the delay in getting back to you. Thank you again for your review comments. I did my best trying to get the right combination of matchers that limit the candidates and allow the exceptions that we want. I wasn't successful in figuring out a way to exempt static references to non-trivial destructor classes that don't have the lifetime extension (see comment).

clang-tools-extra/clang-tidy/fuchsia/GlobalVariablesCheck.cpp
36

In the latest revision I narrowed the matching candidates to:

anyOf(hasType(hasCanonicalType(references(qualType()))),
               hasType(arrayType()),
               hasType(cxxRecordDecl(hasNonTrivialDestructor()))),

I found I needed to capture arrays and references in the tests and included those in the limited candidates.

However, after a lot of testing and experimenting with materializeTemporaryExpr and your suggestions, I still couldn't figure out a way to allow references without lifetime extensions. For ex, this test gives a false positive with the latest patch:

// Static references with function scope are allowed if they don't have
// lifetime-extension.
static const NonTriviallyDestructibleClass &ConstRefFuncNtdc = *new NonTriviallyDestructibleClass;

I've been starting to question if this is a general enough use case to include as an exception. Do you think it would be a mistake if this check does not allow static references to non-trivial destructors, regardless of a lifetime extension?

37

I went ahead and combined the two suggestions around the IgnoreVars matching .

clang-tools-extra/test/clang-tidy/checkers/fuchsia/global-variables.cpp
104

I got rid of these scenarios and tested typedef to a reference per your suggestion in the latest patch - hopefully I captured it correctly:

typedef for const reference of non trivial type that is used to exend lfietime of variable (calling function that returns object with non trivial destructor).

Caslyn updated this revision to Diff 535845.Jun 29 2023, 9:20 AM

correct reference in test