Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "NonParamInsideFunctionDeclChecker.h"
6
#include "CustomMatchers.h"
7
8
class NonParamAnnotation : public CustomTypeAnnotation {
9
public:
10
NonParamAnnotation() : CustomTypeAnnotation(moz_non_param, "non-param"){};
11
12
protected:
13
// Adding alignas(_) on a struct implicitly marks it as MOZ_NON_PARAM, due to
14
// MSVC limitations which prevent passing explcitly aligned types by value as
15
// parameters. This overload of hasFakeAnnotation injects fake MOZ_NON_PARAM
16
// annotations onto these types.
17
std::string getImplicitReason(const TagDecl *D) const override {
18
// Check if the decl itself has an AlignedAttr on it.
19
for (const Attr *A : D->attrs()) {
20
if (isa<AlignedAttr>(A)) {
21
return "it has an alignas(_) annotation";
22
}
23
}
24
25
// Check if any of the decl's fields have an AlignedAttr on them.
26
if (auto RD = dyn_cast<RecordDecl>(D)) {
27
for (auto F : RD->fields()) {
28
for (auto A : F->attrs()) {
29
if (isa<AlignedAttr>(A)) {
30
return ("member '" + F->getName() +
31
"' has an alignas(_) annotation")
32
.str();
33
}
34
}
35
}
36
}
37
38
// We don't need to check the types of fields, as the CustomTypeAnnotation
39
// infrastructure will handle that for us.
40
return "";
41
}
42
};
43
NonParamAnnotation NonParam;
44
45
void NonParamInsideFunctionDeclChecker::registerMatchers(
46
MatchFinder *AstMatcher) {
47
AstMatcher->addMatcher(
48
functionDecl(
49
anyOf(allOf(isDefinition(),
50
hasAncestor(
51
classTemplateSpecializationDecl().bind("spec"))),
52
isDefinition()))
53
.bind("func"),
54
this);
55
AstMatcher->addMatcher(lambdaExpr().bind("lambda"), this);
56
}
57
58
void NonParamInsideFunctionDeclChecker::check(
59
const MatchFinder::MatchResult &Result) {
60
static DenseSet<const FunctionDecl *> CheckedFunctionDecls;
61
62
const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func");
63
if (!func) {
64
const LambdaExpr *lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
65
if (lambda) {
66
func = lambda->getCallOperator();
67
}
68
}
69
70
if (!func) {
71
return;
72
}
73
74
if (func->isDeleted()) {
75
return;
76
}
77
78
// We need to skip decls which have these types as parameters in system
79
// headers, because presumably those headers act like an assertion that the
80
// alignment will be preserved in that situation.
81
if (getDeclarationNamespace(func) == "std") {
82
return;
83
}
84
85
if (inThirdPartyPath(func)) {
86
return;
87
}
88
89
// Don't report errors on the same declarations more than once.
90
if (CheckedFunctionDecls.count(func)) {
91
return;
92
}
93
CheckedFunctionDecls.insert(func);
94
95
const ClassTemplateSpecializationDecl *Spec =
96
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("spec");
97
98
for (ParmVarDecl *p : func->parameters()) {
99
QualType T = p->getType().withoutLocalFastQualifiers();
100
if (NonParam.hasEffectiveAnnotation(T)) {
101
diag(p->getLocation(), "Type %0 must not be used as parameter",
102
DiagnosticIDs::Error)
103
<< T;
104
diag(p->getLocation(),
105
"Please consider passing a const reference instead",
106
DiagnosticIDs::Note);
107
108
if (Spec) {
109
diag(Spec->getPointOfInstantiation(),
110
"The bad argument was passed to %0 here", DiagnosticIDs::Note)
111
<< Spec->getSpecializedTemplate();
112
}
113
114
NonParam.dumpAnnotationReason(*this, T, p->getLocation());
115
}
116
}
117
}