Bug 1569681: Part 1 - Add support for moz_static_local_class and moz_trivial_dtor to clang-plugin; r=Ehsan

This patch is in support of adding a variant of Static{Auto,Ref}Ptr for use as
static locals, taking advantage of C++11 "magic statics" such that we can lazily
initialize those variables in a thread-safe way.

In support of those classes, this patch adds two new attributes:

* `moz_static_local_class` to ensure that any instantiations of that class only
  occur as static local variables;
* `moz_trivial_dtor` to ensure that these classes do not implicitly call `atexit`
  and add a whole bunch of shutdown crap.

`moz_static_local_class` works similarly to `moz_global_class`, except that its
object must only instantiate as static locals.

`TrivialDtorChecker` is based on `TrivialCtorDtorChecker`, with the ctor-specific
bits removed.

Differential Revision: https://phabricator.services.mozilla.com/D39717

--HG--
rename : build/clang-plugin/TrivialCtorDtorChecker.cpp => build/clang-plugin/TrivialDtorChecker.cpp
rename : build/clang-plugin/TrivialCtorDtorChecker.h => build/clang-plugin/TrivialDtorChecker.h
extra : moz-landing-system : lando
This commit is contained in:
Aaron Klotz 2019-07-30 18:50:52 +00:00
Родитель bc4352b83c
Коммит b21e723d2e
10 изменённых файлов: 69 добавлений и 0 удалений

Просмотреть файл

@ -34,3 +34,4 @@ CHECK(RefCountedInsideLambdaChecker, "refcounted-inside-lambda")
CHECK(ScopeChecker, "scope")
CHECK(SprintfLiteralChecker, "sprintf-literal")
CHECK(TrivialCtorDtorChecker, "trivial-constructor-destructor")
CHECK(TrivialDtorChecker, "trivial-destructor")

Просмотреть файл

@ -35,4 +35,5 @@
#include "ScopeChecker.h"
#include "SprintfLiteralChecker.h"
#include "TrivialCtorDtorChecker.h"
#include "TrivialDtorChecker.h"

Просмотреть файл

@ -24,5 +24,7 @@ ATTR(moz_non_temporary_class)
ATTR(moz_nonheap_class)
ATTR(moz_required_base_method)
ATTR(moz_stack_class)
ATTR(moz_static_local_class)
ATTR(moz_temporary_class)
ATTR(moz_trivial_ctor_dtor)
ATTR(moz_trivial_dtor)

Просмотреть файл

@ -29,6 +29,12 @@ AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) {
return hasCustomAttribute<moz_trivial_ctor_dtor>(&Node);
}
/// This matcher will match any C++ class that is marked as having a trivial
/// destructor.
AST_MATCHER(CXXRecordDecl, hasTrivialDtor) {
return hasCustomAttribute<moz_trivial_dtor>(&Node);
}
AST_MATCHER(CXXConstructExpr, allowsTemporary) {
return hasCustomAttribute<moz_allow_temporary>(Node.getConstructor());
}

Просмотреть файл

@ -16,6 +16,8 @@ CustomTypeAnnotation NonTemporaryClass =
CustomTypeAnnotation(moz_non_temporary_class, "non-temporary");
CustomTypeAnnotation TemporaryClass =
CustomTypeAnnotation(moz_temporary_class, "temporary");
CustomTypeAnnotation StaticLocalClass =
CustomTypeAnnotation(moz_static_local_class, "static-local");
void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, QualType T,
SourceLocation Loc) {

Просмотреть файл

@ -70,5 +70,6 @@ extern CustomTypeAnnotation NonHeapClass;
extern CustomTypeAnnotation HeapClass;
extern CustomTypeAnnotation NonTemporaryClass;
extern CustomTypeAnnotation TemporaryClass;
extern CustomTypeAnnotation StaticLocalClass;
#endif

Просмотреть файл

@ -37,6 +37,7 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
AllocationVariety Variety = AV_None;
SourceLocation Loc;
QualType T;
bool IsStaticLocal = false;
if (const ParmVarDecl *D =
Result.Nodes.getNodeAs<ParmVarDecl>("node")) {
@ -66,6 +67,7 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
}
T = D->getType();
Loc = D->getBeginLoc();
IsStaticLocal = D->isStaticLocal();
} else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
// New allocates things on the heap.
// We don't consider placement new to do anything, as it doesn't actually
@ -126,6 +128,8 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
const char *NonHeap = "variable of type %0 is not valid on the heap";
const char *NonTemporary = "variable of type %0 is not valid in a temporary";
const char *Temporary = "variable of type %0 is only valid as a temporary";
const char *StaticLocal = "variable of type %0 is only valid as a static "
"local";
const char *StackNote =
"value incorrectly allocated in an automatic variable";
@ -142,12 +146,18 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
StackClass.reportErrorIfPresent(*this, T, Loc, Stack, GlobalNote);
HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, GlobalNote);
TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, GlobalNote);
if (!IsStaticLocal) {
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
GlobalNote);
}
break;
case AV_Automatic:
GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, StackNote);
HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, StackNote);
TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, StackNote);
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
StackNote);
break;
case AV_Temporary:
@ -155,6 +165,8 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, TemporaryNote);
NonTemporaryClass.reportErrorIfPresent(*this, T, Loc, NonTemporary,
TemporaryNote);
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
TemporaryNote);
break;
case AV_Heap:
@ -162,6 +174,7 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
StackClass.reportErrorIfPresent(*this, T, Loc, Stack, HeapNote);
NonHeapClass.reportErrorIfPresent(*this, T, Loc, NonHeap, HeapNote);
TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, HeapNote);
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, HeapNote);
break;
}
}

Просмотреть файл

@ -0,0 +1,24 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TrivialDtorChecker.h"
#include "CustomMatchers.h"
void TrivialDtorChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl(hasTrivialDtor()).bind("node"),
this);
}
void TrivialDtorChecker::check(const MatchFinder::MatchResult &Result) {
const char *Error = "class %0 must have a trivial destructor";
const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
if (!Node->hasDefinition()) {
return;
}
bool BadDtor = !Node->hasTrivialDestructor();
if (BadDtor)
diag(Node->getBeginLoc(), Error, DiagnosticIDs::Error) << Node;
}

Просмотреть файл

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TrivialDtorChecker_h__
#define TrivialDtorChecker_h__
#include "plugin.h"
class TrivialDtorChecker : public BaseCheck {
public:
TrivialDtorChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};
#endif

Просмотреть файл

@ -40,6 +40,7 @@ HOST_SOURCES += [
'ScopeChecker.cpp',
'SprintfLiteralChecker.cpp',
'TrivialCtorDtorChecker.cpp',
'TrivialDtorChecker.cpp',
'VariableUsageHelpers.cpp',
]