зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
bc4352b83c
Коммит
b21e723d2e
|
@ -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',
|
||||
]
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче