/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file implements decl-related attribute processing. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "clang/AST/ASTConsumer.h" |
14 | | #include "clang/AST/ASTContext.h" |
15 | | #include "clang/AST/ASTMutationListener.h" |
16 | | #include "clang/AST/CXXInheritance.h" |
17 | | #include "clang/AST/DeclCXX.h" |
18 | | #include "clang/AST/DeclObjC.h" |
19 | | #include "clang/AST/DeclTemplate.h" |
20 | | #include "clang/AST/Expr.h" |
21 | | #include "clang/AST/ExprCXX.h" |
22 | | #include "clang/AST/Mangle.h" |
23 | | #include "clang/AST/RecursiveASTVisitor.h" |
24 | | #include "clang/AST/Type.h" |
25 | | #include "clang/Basic/CharInfo.h" |
26 | | #include "clang/Basic/SourceLocation.h" |
27 | | #include "clang/Basic/SourceManager.h" |
28 | | #include "clang/Basic/TargetBuiltins.h" |
29 | | #include "clang/Basic/TargetInfo.h" |
30 | | #include "clang/Lex/Preprocessor.h" |
31 | | #include "clang/Sema/DeclSpec.h" |
32 | | #include "clang/Sema/DelayedDiagnostic.h" |
33 | | #include "clang/Sema/Initialization.h" |
34 | | #include "clang/Sema/Lookup.h" |
35 | | #include "clang/Sema/ParsedAttr.h" |
36 | | #include "clang/Sema/Scope.h" |
37 | | #include "clang/Sema/ScopeInfo.h" |
38 | | #include "clang/Sema/SemaInternal.h" |
39 | | #include "llvm/ADT/Optional.h" |
40 | | #include "llvm/ADT/STLExtras.h" |
41 | | #include "llvm/ADT/StringExtras.h" |
42 | | #include "llvm/IR/Assumptions.h" |
43 | | #include "llvm/Support/MathExtras.h" |
44 | | #include "llvm/Support/raw_ostream.h" |
45 | | |
46 | | using namespace clang; |
47 | | using namespace sema; |
48 | | |
49 | | namespace AttributeLangSupport { |
50 | | enum LANG { |
51 | | C, |
52 | | Cpp, |
53 | | ObjC |
54 | | }; |
55 | | } // end namespace AttributeLangSupport |
56 | | |
57 | | //===----------------------------------------------------------------------===// |
58 | | // Helper functions |
59 | | //===----------------------------------------------------------------------===// |
60 | | |
61 | | /// isFunctionOrMethod - Return true if the given decl has function |
62 | | /// type (function or function-typed variable) or an Objective-C |
63 | | /// method. |
64 | 78.1k | static bool isFunctionOrMethod(const Decl *D) { |
65 | 78.1k | return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D)326 ; |
66 | 78.1k | } |
67 | | |
68 | | /// Return true if the given decl has function type (function or |
69 | | /// function-typed variable) or an Objective-C method or a block. |
70 | 77.9k | static bool isFunctionOrMethodOrBlock(const Decl *D) { |
71 | 77.9k | return isFunctionOrMethod(D) || isa<BlockDecl>(D)1 ; |
72 | 77.9k | } |
73 | | |
74 | | /// Return true if the given decl has a declarator that should have |
75 | | /// been processed by Sema::GetTypeForDeclarator. |
76 | 16.0k | static bool hasDeclarator(const Decl *D) { |
77 | | // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. |
78 | 16.0k | return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D)359 || isa<TypedefNameDecl>(D)350 || |
79 | 204 | isa<ObjCPropertyDecl>(D); |
80 | 16.0k | } |
81 | | |
82 | | /// hasFunctionProto - Return true if the given decl has a argument |
83 | | /// information. This decl should have already passed |
84 | | /// isFunctionOrMethod or isFunctionOrMethodOrBlock. |
85 | 78.1k | static bool hasFunctionProto(const Decl *D) { |
86 | 78.1k | if (const FunctionType *FnTy = D->getFunctionType()) |
87 | 77.8k | return isa<FunctionProtoType>(FnTy); |
88 | 330 | return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D)9 ; |
89 | 330 | } |
90 | | |
91 | | /// getFunctionOrMethodNumParams - Return number of function or method |
92 | | /// parameters. It is an error to call this on a K&R function (use |
93 | | /// hasFunctionProto first). |
94 | 186k | static unsigned getFunctionOrMethodNumParams(const Decl *D) { |
95 | 186k | if (const FunctionType *FnTy = D->getFunctionType()) |
96 | 182k | return cast<FunctionProtoType>(FnTy)->getNumParams(); |
97 | 3.88k | if (const auto *BD = dyn_cast<BlockDecl>(D)) |
98 | 17 | return BD->getNumParams(); |
99 | 3.87k | return cast<ObjCMethodDecl>(D)->param_size(); |
100 | 3.87k | } |
101 | | |
102 | | static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, |
103 | 70.6k | unsigned Idx) { |
104 | 70.6k | if (const auto *FD = dyn_cast<FunctionDecl>(D)) |
105 | 70.2k | return FD->getParamDecl(Idx); |
106 | 344 | if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) |
107 | 29 | return MD->getParamDecl(Idx); |
108 | 315 | if (const auto *BD = dyn_cast<BlockDecl>(D)) |
109 | 16 | return BD->getParamDecl(Idx); |
110 | 299 | return nullptr; |
111 | 299 | } |
112 | | |
113 | 109k | static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { |
114 | 109k | if (const FunctionType *FnTy = D->getFunctionType()) |
115 | 105k | return cast<FunctionProtoType>(FnTy)->getParamType(Idx); |
116 | 3.85k | if (const auto *BD = dyn_cast<BlockDecl>(D)) |
117 | 8 | return BD->getParamDecl(Idx)->getType(); |
118 | | |
119 | 3.84k | return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType(); |
120 | 3.84k | } |
121 | | |
122 | 70.5k | static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { |
123 | 70.5k | if (auto *PVD = getFunctionOrMethodParam(D, Idx)) |
124 | 70.2k | return PVD->getSourceRange(); |
125 | 299 | return SourceRange(); |
126 | 299 | } |
127 | | |
128 | 16.4k | static QualType getFunctionOrMethodResultType(const Decl *D) { |
129 | 16.4k | if (const FunctionType *FnTy = D->getFunctionType()) |
130 | 16.1k | return FnTy->getReturnType(); |
131 | 308 | return cast<ObjCMethodDecl>(D)->getReturnType(); |
132 | 308 | } |
133 | | |
134 | 80 | static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { |
135 | 80 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) |
136 | 76 | return FD->getReturnTypeSourceRange(); |
137 | 4 | if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) |
138 | 4 | return MD->getReturnTypeSourceRange(); |
139 | 0 | return SourceRange(); |
140 | 0 | } |
141 | | |
142 | 96.9k | static bool isFunctionOrMethodVariadic(const Decl *D) { |
143 | 96.9k | if (const FunctionType *FnTy = D->getFunctionType()) |
144 | 93.9k | return cast<FunctionProtoType>(FnTy)->isVariadic(); |
145 | 2.96k | if (const auto *BD = dyn_cast<BlockDecl>(D)) |
146 | 6 | return BD->isVariadic(); |
147 | 2.96k | return cast<ObjCMethodDecl>(D)->isVariadic(); |
148 | 2.96k | } |
149 | | |
150 | 115k | static bool isInstanceMethod(const Decl *D) { |
151 | 115k | if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D)) |
152 | 256 | return MethodDecl->isInstance(); |
153 | 115k | return false; |
154 | 115k | } |
155 | | |
156 | 6.79k | static inline bool isNSStringType(QualType T, ASTContext &Ctx) { |
157 | 6.79k | const auto *PT = T->getAs<ObjCObjectPointerType>(); |
158 | 6.79k | if (!PT) |
159 | 1.41k | return false; |
160 | | |
161 | 5.37k | ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); |
162 | 5.37k | if (!Cls) |
163 | 0 | return false; |
164 | | |
165 | 5.37k | IdentifierInfo* ClsName = Cls->getIdentifier(); |
166 | | |
167 | | // FIXME: Should we walk the chain of classes? |
168 | 5.37k | return ClsName == &Ctx.Idents.get("NSString") || |
169 | 0 | ClsName == &Ctx.Idents.get("NSMutableString"); |
170 | 5.37k | } |
171 | | |
172 | 2.60k | static inline bool isCFStringType(QualType T, ASTContext &Ctx) { |
173 | 2.60k | const auto *PT = T->getAs<PointerType>(); |
174 | 2.60k | if (!PT) |
175 | 3 | return false; |
176 | | |
177 | 2.60k | const auto *RT = PT->getPointeeType()->getAs<RecordType>(); |
178 | 2.60k | if (!RT) |
179 | 526 | return false; |
180 | | |
181 | 2.07k | const RecordDecl *RD = RT->getDecl(); |
182 | 2.07k | if (RD->getTagKind() != TTK_Struct) |
183 | 0 | return false; |
184 | | |
185 | 2.07k | return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); |
186 | 2.07k | } |
187 | | |
188 | 48.4M | static unsigned getNumAttributeArgs(const ParsedAttr &AL) { |
189 | | // FIXME: Include the type in the argument list. |
190 | 48.4M | return AL.getNumArgs() + AL.hasParsedType(); |
191 | 48.4M | } |
192 | | |
193 | | template <typename Compare> |
194 | | static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, |
195 | | unsigned Num, unsigned Diag, |
196 | 48.4M | Compare Comp) { |
197 | 48.4M | if (Comp(getNumAttributeArgs(AL), Num)) { |
198 | 361 | S.Diag(AL.getLoc(), Diag) << AL << Num; |
199 | 361 | return false; |
200 | 361 | } |
201 | | |
202 | 48.4M | return true; |
203 | 48.4M | } SemaDeclAttr.cpp:bool checkAttributeNumArgsImpl<std::__1::not_equal_to<unsigned int> >(clang::Sema&, clang::ParsedAttr const&, unsigned int, unsigned int, std::__1::not_equal_to<unsigned int>) Line | Count | Source | 196 | 48.3M | Compare Comp) { | 197 | 48.3M | if (Comp(getNumAttributeArgs(AL), Num)) { | 198 | 272 | S.Diag(AL.getLoc(), Diag) << AL << Num; | 199 | 272 | return false; | 200 | 272 | } | 201 | | | 202 | 48.3M | return true; | 203 | 48.3M | } |
SemaDeclAttr.cpp:bool checkAttributeNumArgsImpl<std::__1::less<unsigned int> >(clang::Sema&, clang::ParsedAttr const&, unsigned int, unsigned int, std::__1::less<unsigned int>) Line | Count | Source | 196 | 19.0k | Compare Comp) { | 197 | 19.0k | if (Comp(getNumAttributeArgs(AL), Num)) { | 198 | 70 | S.Diag(AL.getLoc(), Diag) << AL << Num; | 199 | 70 | return false; | 200 | 70 | } | 201 | | | 202 | 18.9k | return true; | 203 | 18.9k | } |
SemaDeclAttr.cpp:bool checkAttributeNumArgsImpl<std::__1::greater<unsigned int> >(clang::Sema&, clang::ParsedAttr const&, unsigned int, unsigned int, std::__1::greater<unsigned int>) Line | Count | Source | 196 | 126k | Compare Comp) { | 197 | 126k | if (Comp(getNumAttributeArgs(AL), Num)) { | 198 | 19 | S.Diag(AL.getLoc(), Diag) << AL << Num; | 199 | 19 | return false; | 200 | 19 | } | 201 | | | 202 | 126k | return true; | 203 | 126k | } |
|
204 | | |
205 | | /// Check if the attribute has exactly as many args as Num. May |
206 | | /// output an error. |
207 | 48.3M | static bool checkAttributeNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { |
208 | 48.3M | return checkAttributeNumArgsImpl(S, AL, Num, |
209 | 48.3M | diag::err_attribute_wrong_number_arguments, |
210 | 48.3M | std::not_equal_to<unsigned>()); |
211 | 48.3M | } |
212 | | |
213 | | /// Check if the attribute has at least as many args as Num. May |
214 | | /// output an error. |
215 | | static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL, |
216 | 19.0k | unsigned Num) { |
217 | 19.0k | return checkAttributeNumArgsImpl(S, AL, Num, |
218 | 19.0k | diag::err_attribute_too_few_arguments, |
219 | 19.0k | std::less<unsigned>()); |
220 | 19.0k | } |
221 | | |
222 | | /// Check if the attribute has at most as many args as Num. May |
223 | | /// output an error. |
224 | | static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL, |
225 | 126k | unsigned Num) { |
226 | 126k | return checkAttributeNumArgsImpl(S, AL, Num, |
227 | 126k | diag::err_attribute_too_many_arguments, |
228 | 126k | std::greater<unsigned>()); |
229 | 126k | } |
230 | | |
231 | | /// A helper function to provide Attribute Location for the Attr types |
232 | | /// AND the ParsedAttr. |
233 | | template <typename AttrInfo> |
234 | | static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation> |
235 | 23 | getAttrLoc(const AttrInfo &AL) { |
236 | 23 | return AL.getLocation(); |
237 | 23 | } SemaDeclAttr.cpp:std::__1::enable_if<std::is_base_of<clang::Attr, clang::AMDGPUFlatWorkGroupSizeAttr>::value, clang::SourceLocation>::type getAttrLoc<clang::AMDGPUFlatWorkGroupSizeAttr>(clang::AMDGPUFlatWorkGroupSizeAttr const&) Line | Count | Source | 235 | 9 | getAttrLoc(const AttrInfo &AL) { | 236 | 9 | return AL.getLocation(); | 237 | 9 | } |
SemaDeclAttr.cpp:std::__1::enable_if<std::is_base_of<clang::Attr, clang::AMDGPUWavesPerEUAttr>::value, clang::SourceLocation>::type getAttrLoc<clang::AMDGPUWavesPerEUAttr>(clang::AMDGPUWavesPerEUAttr const&) Line | Count | Source | 235 | 9 | getAttrLoc(const AttrInfo &AL) { | 236 | 9 | return AL.getLocation(); | 237 | 9 | } |
SemaDeclAttr.cpp:std::__1::enable_if<std::is_base_of<clang::Attr, clang::AllocAlignAttr>::value, clang::SourceLocation>::type getAttrLoc<clang::AllocAlignAttr>(clang::AllocAlignAttr const&) Line | Count | Source | 235 | 5 | getAttrLoc(const AttrInfo &AL) { | 236 | 5 | return AL.getLocation(); | 237 | 5 | } |
|
238 | 83 | static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } |
239 | | |
240 | | /// If Expr is a valid integer constant, get the value of the integer |
241 | | /// expression and return success or failure. May output an error. |
242 | | /// |
243 | | /// Negative argument is implicitly converted to unsigned, unless |
244 | | /// \p StrictlyUnsigned is true. |
245 | | template <typename AttrInfo> |
246 | | static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, |
247 | | uint32_t &Val, unsigned Idx = UINT_MAX, |
248 | 1.12M | bool StrictlyUnsigned = false) { |
249 | 1.12M | Optional<llvm::APSInt> I = llvm::APSInt(32); |
250 | 1.12M | if (Expr->isTypeDependent() || Expr->isValueDependent() || |
251 | 1.12M | !(I = Expr->getIntegerConstantExpr(S.Context))) { |
252 | 32 | if (Idx != UINT_MAX) |
253 | 22 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) |
254 | 22 | << &AI << Idx << AANT_ArgumentIntegerConstant |
255 | 22 | << Expr->getSourceRange(); |
256 | 10 | else |
257 | 10 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) |
258 | 10 | << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); |
259 | 32 | return false; |
260 | 32 | } |
261 | | |
262 | 1.12M | if (!I->isIntN(32)) { |
263 | 10 | S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) |
264 | 10 | << I->toString(10, false) << 32 << /* Unsigned */ 1; |
265 | 10 | return false; |
266 | 10 | } |
267 | | |
268 | 1.12M | if (StrictlyUnsigned && I->isSigned()87 && I->isNegative()87 ) { |
269 | 3 | S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) |
270 | 3 | << &AI << /*non-negative*/ 1; |
271 | 3 | return false; |
272 | 3 | } |
273 | | |
274 | 1.12M | Val = (uint32_t)I->getZExtValue(); |
275 | 1.12M | return true; |
276 | 1.12M | } SemaDeclAttr.cpp:bool checkUInt32Argument<clang::AMDGPUFlatWorkGroupSizeAttr>(clang::Sema&, clang::AMDGPUFlatWorkGroupSizeAttr const&, clang::Expr const*, unsigned int&, unsigned int, bool) Line | Count | Source | 248 | 205 | bool StrictlyUnsigned = false) { | 249 | 205 | Optional<llvm::APSInt> I = llvm::APSInt(32); | 250 | 205 | if (Expr->isTypeDependent() || Expr->isValueDependent() || | 251 | 205 | !(I = Expr->getIntegerConstantExpr(S.Context))) { | 252 | 9 | if (Idx != UINT_MAX) | 253 | 9 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) | 254 | 9 | << &AI << Idx << AANT_ArgumentIntegerConstant | 255 | 9 | << Expr->getSourceRange(); | 256 | 0 | else | 257 | 0 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) | 258 | 0 | << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); | 259 | 9 | return false; | 260 | 9 | } | 261 | | | 262 | 196 | if (!I->isIntN(32)) { | 263 | 3 | S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) | 264 | 3 | << I->toString(10, false) << 32 << /* Unsigned */ 1; | 265 | 3 | return false; | 266 | 3 | } | 267 | | | 268 | 193 | if (StrictlyUnsigned && I->isSigned()0 && I->isNegative()0 ) { | 269 | 0 | S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) | 270 | 0 | << &AI << /*non-negative*/ 1; | 271 | 0 | return false; | 272 | 0 | } | 273 | | | 274 | 193 | Val = (uint32_t)I->getZExtValue(); | 275 | 193 | return true; | 276 | 193 | } |
SemaDeclAttr.cpp:bool checkUInt32Argument<clang::AMDGPUWavesPerEUAttr>(clang::Sema&, clang::AMDGPUWavesPerEUAttr const&, clang::Expr const*, unsigned int&, unsigned int, bool) Line | Count | Source | 248 | 192 | bool StrictlyUnsigned = false) { | 249 | 192 | Optional<llvm::APSInt> I = llvm::APSInt(32); | 250 | 192 | if (Expr->isTypeDependent() || Expr->isValueDependent() || | 251 | 192 | !(I = Expr->getIntegerConstantExpr(S.Context))) { | 252 | 9 | if (Idx != UINT_MAX) | 253 | 9 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) | 254 | 9 | << &AI << Idx << AANT_ArgumentIntegerConstant | 255 | 9 | << Expr->getSourceRange(); | 256 | 0 | else | 257 | 0 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) | 258 | 0 | << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); | 259 | 9 | return false; | 260 | 9 | } | 261 | | | 262 | 183 | if (!I->isIntN(32)) { | 263 | 3 | S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) | 264 | 3 | << I->toString(10, false) << 32 << /* Unsigned */ 1; | 265 | 3 | return false; | 266 | 3 | } | 267 | | | 268 | 180 | if (StrictlyUnsigned && I->isSigned()0 && I->isNegative()0 ) { | 269 | 0 | S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) | 270 | 0 | << &AI << /*non-negative*/ 1; | 271 | 0 | return false; | 272 | 0 | } | 273 | | | 274 | 180 | Val = (uint32_t)I->getZExtValue(); | 275 | 180 | return true; | 276 | 180 | } |
SemaDeclAttr.cpp:bool checkUInt32Argument<clang::ParsedAttr>(clang::Sema&, clang::ParsedAttr const&, clang::Expr const*, unsigned int&, unsigned int, bool) Line | Count | Source | 248 | 1.12M | bool StrictlyUnsigned = false) { | 249 | 1.12M | Optional<llvm::APSInt> I = llvm::APSInt(32); | 250 | 1.12M | if (Expr->isTypeDependent() || Expr->isValueDependent() || | 251 | 1.12M | !(I = Expr->getIntegerConstantExpr(S.Context))) { | 252 | 14 | if (Idx != UINT_MAX) | 253 | 4 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) | 254 | 4 | << &AI << Idx << AANT_ArgumentIntegerConstant | 255 | 4 | << Expr->getSourceRange(); | 256 | 10 | else | 257 | 10 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) | 258 | 10 | << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); | 259 | 14 | return false; | 260 | 14 | } | 261 | | | 262 | 1.12M | if (!I->isIntN(32)) { | 263 | 4 | S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) | 264 | 4 | << I->toString(10, false) << 32 << /* Unsigned */ 1; | 265 | 4 | return false; | 266 | 4 | } | 267 | | | 268 | 1.12M | if (StrictlyUnsigned && I->isSigned()87 && I->isNegative()87 ) { | 269 | 3 | S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) | 270 | 3 | << &AI << /*non-negative*/ 1; | 271 | 3 | return false; | 272 | 3 | } | 273 | | | 274 | 1.12M | Val = (uint32_t)I->getZExtValue(); | 275 | 1.12M | return true; | 276 | 1.12M | } |
|
277 | | |
278 | | /// Wrapper around checkUInt32Argument, with an extra check to be sure |
279 | | /// that the result will fit into a regular (signed) int. All args have the same |
280 | | /// purpose as they do in checkUInt32Argument. |
281 | | template <typename AttrInfo> |
282 | | static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr, |
283 | 6.12k | int &Val, unsigned Idx = UINT_MAX) { |
284 | 6.12k | uint32_t UVal; |
285 | 6.12k | if (!checkUInt32Argument(S, AI, Expr, UVal, Idx)) |
286 | 2 | return false; |
287 | | |
288 | 6.12k | if (UVal > (uint32_t)std::numeric_limits<int>::max()) { |
289 | 1 | llvm::APSInt I(32); // for toString |
290 | 1 | I = UVal; |
291 | 1 | S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) |
292 | 1 | << I.toString(10, false) << 32 << /* Unsigned */ 0; |
293 | 1 | return false; |
294 | 1 | } |
295 | | |
296 | 6.12k | Val = UVal; |
297 | 6.12k | return true; |
298 | 6.12k | } |
299 | | |
300 | | /// Diagnose mutually exclusive attributes when present on a given |
301 | | /// declaration. Returns true if diagnosed. |
302 | | template <typename AttrTy> |
303 | 8.23M | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { |
304 | 8.23M | if (const auto *A = D->getAttr<AttrTy>()) { |
305 | 65 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; |
306 | 65 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); |
307 | 65 | return true; |
308 | 65 | } |
309 | 8.23M | return false; |
310 | 8.23M | } SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::Mips16Attr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 28 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 28 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 4 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 4 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 4 | return true; | 308 | 4 | } | 309 | 24 | return false; | 310 | 24 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::MicroMipsAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 11 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 11 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 10 | return false; | 310 | 10 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::MipsInterruptAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 10 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 10 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 8 | return false; | 310 | 8 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::MipsShortCallAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 16 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 16 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 14 | return false; | 310 | 14 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::MipsLongCallAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 16 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 16 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 14 | return false; | 310 | 14 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::NotTailCalledAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 8.22M | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 8.22M | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 8.22M | return false; | 310 | 8.22M | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDASharedAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 314 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 314 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 6 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 6 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 6 | return true; | 308 | 6 | } | 309 | 308 | return false; | 310 | 308 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::HIPManagedAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 540 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 540 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 8 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 8 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 8 | return true; | 308 | 8 | } | 309 | 532 | return false; | 310 | 532 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDADeviceAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 299 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 299 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 297 | return false; | 310 | 297 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDAHostAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 297 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 297 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 295 | return false; | 310 | 295 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDAGlobalAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 3.35k | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 3.35k | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 4 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 4 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 4 | return true; | 308 | 4 | } | 309 | 3.34k | return false; | 310 | 3.34k | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDAConstantAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 368 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 368 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 8 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 8 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 8 | return true; | 308 | 8 | } | 309 | 360 | return false; | 310 | 360 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDADeviceBuiltinTextureTypeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 10 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 10 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 0 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 0 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 0 | return true; | 308 | 0 | } | 309 | 10 | return false; | 310 | 10 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CUDADeviceBuiltinSurfaceTypeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 10 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 10 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 0 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 0 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 0 | return true; | 308 | 0 | } | 309 | 10 | return false; | 310 | 10 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::HotAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 3.79k | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 3.79k | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 3.79k | return false; | 310 | 3.79k | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::ColdAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 15 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 15 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 14 | return false; | 310 | 14 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::DisableTailCallsAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 31 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 31 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 30 | return false; | 310 | 30 | } |
Unexecuted instantiation: SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CFUnknownTransferAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CFAuditedTransferAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 1 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 1 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 0 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 0 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 0 | return true; | 308 | 0 | } | 309 | 1 | return false; | 310 | 1 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::NoSpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 27 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 27 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 25 | return false; | 310 | 25 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::SpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 27 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 27 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 2 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 2 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 2 | return true; | 308 | 2 | } | 309 | 25 | return false; | 310 | 25 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::AlwaysInlineAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 668 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 668 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 667 | return false; | 310 | 667 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::NakedAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 420 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 420 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 419 | return false; | 310 | 419 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::PointerAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 28 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 28 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 27 | return false; | 310 | 27 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::OwnerAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 16 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 16 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 15 | return false; | 310 | 15 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::NoDestroyAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 28 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 28 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 4 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 4 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 4 | return true; | 308 | 4 | } | 309 | 24 | return false; | 310 | 24 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::AlwaysDestroyAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 42 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 42 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 4 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 4 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 4 | return true; | 308 | 4 | } | 309 | 38 | return false; | 310 | 38 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::InternalLinkageAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 9 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 9 | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 1 | return true; | 308 | 1 | } | 309 | 8 | return false; | 310 | 8 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CommonAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 303 | 1.16k | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { | 304 | 1.16k | if (const auto *A = D->getAttr<AttrTy>()) { | 305 | 3 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; | 306 | 3 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 307 | 3 | return true; | 308 | 3 | } | 309 | 1.16k | return false; | 310 | 1.16k | } |
|
311 | | |
312 | | template <typename AttrTy> |
313 | 11 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { |
314 | 11 | if (const auto *A = D->getAttr<AttrTy>()) { |
315 | 4 | S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL |
316 | 4 | << A; |
317 | 4 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); |
318 | 4 | return true; |
319 | 4 | } |
320 | 7 | return false; |
321 | 7 | } SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::InternalLinkageAttr>(clang::Sema&, clang::Decl*, clang::Attr const&) Line | Count | Source | 313 | 1 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { | 314 | 1 | if (const auto *A = D->getAttr<AttrTy>()) { | 315 | 1 | S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL | 316 | 1 | << A; | 317 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 318 | 1 | return true; | 319 | 1 | } | 320 | 0 | return false; | 321 | 0 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::CommonAttr>(clang::Sema&, clang::Decl*, clang::Attr const&) Line | Count | Source | 313 | 8 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { | 314 | 8 | if (const auto *A = D->getAttr<AttrTy>()) { | 315 | 1 | S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL | 316 | 1 | << A; | 317 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 318 | 1 | return true; | 319 | 1 | } | 320 | 7 | return false; | 321 | 7 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::SpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::Attr const&) Line | Count | Source | 313 | 1 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { | 314 | 1 | if (const auto *A = D->getAttr<AttrTy>()) { | 315 | 1 | S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL | 316 | 1 | << A; | 317 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 318 | 1 | return true; | 319 | 1 | } | 320 | 0 | return false; | 321 | 0 | } |
SemaDeclAttr.cpp:bool checkAttrMutualExclusion<clang::NoSpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::Attr const&) Line | Count | Source | 313 | 1 | static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { | 314 | 1 | if (const auto *A = D->getAttr<AttrTy>()) { | 315 | 1 | S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL | 316 | 1 | << A; | 317 | 1 | S.Diag(A->getLocation(), diag::note_conflicting_attribute); | 318 | 1 | return true; | 319 | 1 | } | 320 | 0 | return false; | 321 | 0 | } |
|
322 | | |
323 | | /// Check if IdxExpr is a valid parameter index for a function or |
324 | | /// instance method D. May output an error. |
325 | | /// |
326 | | /// \returns true if IdxExpr is a valid index. |
327 | | template <typename AttrInfo> |
328 | | static bool checkFunctionOrMethodParameterIndex( |
329 | | Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum, |
330 | 77.9k | const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { |
331 | 77.9k | assert(isFunctionOrMethodOrBlock(D)); |
332 | | |
333 | | // In C++ the implicit 'this' function parameter also counts. |
334 | | // Parameters are counted from one. |
335 | 77.9k | bool HP = hasFunctionProto(D); |
336 | 77.9k | bool HasImplicitThisParam = isInstanceMethod(D); |
337 | 77.9k | bool IV = HP && isFunctionOrMethodVariadic(D)77.9k ; |
338 | 77.9k | unsigned NumParams = |
339 | 77.9k | (HP ? getFunctionOrMethodNumParams(D) : 05 ) + HasImplicitThisParam; |
340 | | |
341 | 77.9k | Optional<llvm::APSInt> IdxInt; |
342 | 77.9k | if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || |
343 | 77.9k | !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { |
344 | 13 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) |
345 | 13 | << &AI << AttrArgNum << AANT_ArgumentIntegerConstant |
346 | 13 | << IdxExpr->getSourceRange(); |
347 | 13 | return false; |
348 | 13 | } |
349 | | |
350 | 77.9k | unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); |
351 | 77.9k | if (IdxSource < 1 || (77.9k !IV77.9k && IdxSource > NumParams77.2k )) { |
352 | 51 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) |
353 | 51 | << &AI << AttrArgNum << IdxExpr->getSourceRange(); |
354 | 51 | return false; |
355 | 51 | } |
356 | 77.8k | if (HasImplicitThisParam && !CanIndexImplicitThis75 ) { |
357 | 72 | if (IdxSource == 1) { |
358 | 6 | S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) |
359 | 6 | << &AI << IdxExpr->getSourceRange(); |
360 | 6 | return false; |
361 | 6 | } |
362 | 77.8k | } |
363 | | |
364 | 77.8k | Idx = ParamIdx(IdxSource, D); |
365 | 77.8k | return true; |
366 | 77.8k | } SemaDeclAttr.cpp:bool checkFunctionOrMethodParameterIndex<clang::ParsedAttr>(clang::Sema&, clang::Decl const*, clang::ParsedAttr const&, unsigned int, clang::Expr const*, clang::ParamIdx&, bool) Line | Count | Source | 330 | 77.8k | const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { | 331 | 77.8k | assert(isFunctionOrMethodOrBlock(D)); | 332 | | | 333 | | // In C++ the implicit 'this' function parameter also counts. | 334 | | // Parameters are counted from one. | 335 | 77.8k | bool HP = hasFunctionProto(D); | 336 | 77.8k | bool HasImplicitThisParam = isInstanceMethod(D); | 337 | 77.8k | bool IV = HP && isFunctionOrMethodVariadic(D)77.8k ; | 338 | 77.8k | unsigned NumParams = | 339 | 77.8k | (HP ? getFunctionOrMethodNumParams(D) : 05 ) + HasImplicitThisParam; | 340 | | | 341 | 77.8k | Optional<llvm::APSInt> IdxInt; | 342 | 77.8k | if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || | 343 | 77.8k | !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { | 344 | 11 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) | 345 | 11 | << &AI << AttrArgNum << AANT_ArgumentIntegerConstant | 346 | 11 | << IdxExpr->getSourceRange(); | 347 | 11 | return false; | 348 | 11 | } | 349 | | | 350 | 77.8k | unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); | 351 | 77.8k | if (IdxSource < 1 || (77.8k !IV77.8k && IdxSource > NumParams77.1k )) { | 352 | 49 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) | 353 | 49 | << &AI << AttrArgNum << IdxExpr->getSourceRange(); | 354 | 49 | return false; | 355 | 49 | } | 356 | 77.8k | if (HasImplicitThisParam && !CanIndexImplicitThis64 ) { | 357 | 61 | if (IdxSource == 1) { | 358 | 5 | S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) | 359 | 5 | << &AI << IdxExpr->getSourceRange(); | 360 | 5 | return false; | 361 | 5 | } | 362 | 77.8k | } | 363 | | | 364 | 77.8k | Idx = ParamIdx(IdxSource, D); | 365 | 77.8k | return true; | 366 | 77.8k | } |
SemaDeclAttr.cpp:bool checkFunctionOrMethodParameterIndex<clang::AllocAlignAttr>(clang::Sema&, clang::Decl const*, clang::AllocAlignAttr const&, unsigned int, clang::Expr const*, clang::ParamIdx&, bool) Line | Count | Source | 330 | 42 | const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { | 331 | 42 | assert(isFunctionOrMethodOrBlock(D)); | 332 | | | 333 | | // In C++ the implicit 'this' function parameter also counts. | 334 | | // Parameters are counted from one. | 335 | 42 | bool HP = hasFunctionProto(D); | 336 | 42 | bool HasImplicitThisParam = isInstanceMethod(D); | 337 | 42 | bool IV = HP && isFunctionOrMethodVariadic(D); | 338 | 42 | unsigned NumParams = | 339 | 42 | (HP ? getFunctionOrMethodNumParams(D) : 00 ) + HasImplicitThisParam; | 340 | | | 341 | 42 | Optional<llvm::APSInt> IdxInt; | 342 | 42 | if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || | 343 | 41 | !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { | 344 | 2 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) | 345 | 2 | << &AI << AttrArgNum << AANT_ArgumentIntegerConstant | 346 | 2 | << IdxExpr->getSourceRange(); | 347 | 2 | return false; | 348 | 2 | } | 349 | | | 350 | 40 | unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); | 351 | 40 | if (IdxSource < 1 || (39 !IV39 && IdxSource > NumParams39 )) { | 352 | 2 | S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) | 353 | 2 | << &AI << AttrArgNum << IdxExpr->getSourceRange(); | 354 | 2 | return false; | 355 | 2 | } | 356 | 38 | if (HasImplicitThisParam && !CanIndexImplicitThis11 ) { | 357 | 11 | if (IdxSource == 1) { | 358 | 1 | S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) | 359 | 1 | << &AI << IdxExpr->getSourceRange(); | 360 | 1 | return false; | 361 | 1 | } | 362 | 37 | } | 363 | | | 364 | 37 | Idx = ParamIdx(IdxSource, D); | 365 | 37 | return true; | 366 | 37 | } |
|
367 | | |
368 | | /// Check if the argument \p ArgNum of \p Attr is a ASCII string literal. |
369 | | /// If not emit an error and return false. If the argument is an identifier it |
370 | | /// will emit an error with a fixit hint and treat it as if it was a string |
371 | | /// literal. |
372 | | bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, |
373 | | StringRef &Str, |
374 | 2.90M | SourceLocation *ArgLocation) { |
375 | | // Look for identifiers. If we have one emit a hint to fix it to a literal. |
376 | 2.90M | if (AL.isArgIdent(ArgNum)) { |
377 | 11 | IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum); |
378 | 11 | Diag(Loc->Loc, diag::err_attribute_argument_type) |
379 | 11 | << AL << AANT_ArgumentString |
380 | 11 | << FixItHint::CreateInsertion(Loc->Loc, "\"") |
381 | 11 | << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\""); |
382 | 11 | Str = Loc->Ident->getName(); |
383 | 11 | if (ArgLocation) |
384 | 8 | *ArgLocation = Loc->Loc; |
385 | 11 | return true; |
386 | 11 | } |
387 | | |
388 | | // Now check for an actual string literal. |
389 | 2.90M | Expr *ArgExpr = AL.getArgAsExpr(ArgNum); |
390 | 2.90M | const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); |
391 | 2.90M | if (ArgLocation) |
392 | 2.86M | *ArgLocation = ArgExpr->getBeginLoc(); |
393 | | |
394 | 2.90M | if (!Literal || !Literal->isAscii()2.90M ) { |
395 | 30 | Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type) |
396 | 30 | << AL << AANT_ArgumentString; |
397 | 30 | return false; |
398 | 30 | } |
399 | | |
400 | 2.90M | Str = Literal->getString(); |
401 | 2.90M | return true; |
402 | 2.90M | } |
403 | | |
404 | | /// Applies the given attribute to the Decl without performing any |
405 | | /// additional semantic checking. |
406 | | template <typename AttrType> |
407 | | static void handleSimpleAttribute(Sema &S, Decl *D, |
408 | 123k | const AttributeCommonInfo &CI) { |
409 | 123k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); |
410 | 123k | } SemaDeclAttr.cpp:void handleSimpleAttribute<clang::AVRInterruptAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 2 | const AttributeCommonInfo &CI) { | 409 | 2 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 2 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::Mips16Attr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 8 | const AttributeCommonInfo &CI) { | 409 | 8 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 8 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::MicroMipsAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 3 | const AttributeCommonInfo &CI) { | 409 | 3 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 3 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::MipsLongCallAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 14 | const AttributeCommonInfo &CI) { | 409 | 14 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::MipsShortCallAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 14 | const AttributeCommonInfo &CI) { | 409 | 14 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::AVRSignalAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 2 | const AttributeCommonInfo &CI) { | 409 | 2 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 2 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::SYCLKernelAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 7 | const AttributeCommonInfo &CI) { | 409 | 7 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 7 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CUDAHostAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 1.06k | const AttributeCommonInfo &CI) { | 409 | 1.06k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 1.06k | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CUDADeviceBuiltinSurfaceTypeAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 10 | const AttributeCommonInfo &CI) { | 409 | 10 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CUDADeviceBuiltinTextureTypeAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 10 | const AttributeCommonInfo &CI) { | 409 | 10 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::ColdAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 3.79k | const AttributeCommonInfo &CI) { | 409 | 3.79k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 3.79k | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::HotAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 14 | const AttributeCommonInfo &CI) { | 409 | 14 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::AnyX86NoCfCheckAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 19 | const AttributeCommonInfo &CI) { | 409 | 19 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 19 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::LeafAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 3 | const AttributeCommonInfo &CI) { | 409 | 3 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 3 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NoThrowAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 33.3k | const AttributeCommonInfo &CI) { | 409 | 33.3k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 33.3k | } |
Unexecuted instantiation: SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CFAuditedTransferAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CFUnknownTransferAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 1 | const AttributeCommonInfo &CI) { | 409 | 1 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 1 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::OSReturnsRetainedOnZeroAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 3 | const AttributeCommonInfo &CI) { | 409 | 3 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 3 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::OSReturnsRetainedOnNonZeroAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 2 | const AttributeCommonInfo &CI) { | 409 | 2 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 2 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NSReturnsAutoreleasedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 6 | const AttributeCommonInfo &CI) { | 409 | 6 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 6 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CFReturnsNotRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 674 | const AttributeCommonInfo &CI) { | 409 | 674 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 674 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NSReturnsNotRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 112 | const AttributeCommonInfo &CI) { | 409 | 112 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 112 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CFReturnsRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 42.7k | const AttributeCommonInfo &CI) { | 409 | 42.7k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 42.7k | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NSReturnsRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 32.1k | const AttributeCommonInfo &CI) { | 409 | 32.1k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 32.1k | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::OSReturnsRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 19 | const AttributeCommonInfo &CI) { | 409 | 19 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 19 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::OSReturnsNotRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 11 | const AttributeCommonInfo &CI) { | 409 | 11 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 11 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::SpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 25 | const AttributeCommonInfo &CI) { | 409 | 25 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 25 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NoSpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 25 | const AttributeCommonInfo &CI) { | 409 | 25 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 25 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::ObjCDirectAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 110 | const AttributeCommonInfo &CI) { | 409 | 110 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 110 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::ObjCNonRuntimeProtocolAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 21 | const AttributeCommonInfo &CI) { | 409 | 21 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 21 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::ObjCDirectMembersAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 20 | const AttributeCommonInfo &CI) { | 409 | 20 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 20 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NotTailCalledAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 667 | const AttributeCommonInfo &CI) { | 409 | 667 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 667 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::DisableTailCallsAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 419 | const AttributeCommonInfo &CI) { | 409 | 419 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 419 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NoMergeAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 8 | const AttributeCommonInfo &CI) { | 409 | 8 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 8 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::SwiftBridgedTypedefAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 418 | const AttributeCommonInfo &CI) { | 409 | 418 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 418 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::SwiftObjCMembersAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 1 | const AttributeCommonInfo &CI) { | 409 | 1 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 1 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::SwiftPrivateAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 4.07k | const AttributeCommonInfo &CI) { | 409 | 4.07k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 4.07k | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::AlwaysDestroyAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 24 | const AttributeCommonInfo &CI) { | 409 | 24 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 24 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NoDestroyAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 38 | const AttributeCommonInfo &CI) { | 409 | 38 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 38 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::LoaderUninitializedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 45 | const AttributeCommonInfo &CI) { | 409 | 45 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 45 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::ObjCExternallyRetainedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 51 | const AttributeCommonInfo &CI) { | 409 | 51 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 51 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::MIGServerRoutineAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 26 | const AttributeCommonInfo &CI) { | 409 | 26 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 26 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::MSAllocatorAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 5 | const AttributeCommonInfo &CI) { | 409 | 5 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 5 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::OSConsumedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 9 | const AttributeCommonInfo &CI) { | 409 | 9 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 9 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::NSConsumedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 494 | const AttributeCommonInfo &CI) { | 409 | 494 | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 494 | } |
SemaDeclAttr.cpp:void handleSimpleAttribute<clang::CFConsumedAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&) Line | Count | Source | 408 | 2.41k | const AttributeCommonInfo &CI) { | 409 | 2.41k | D->addAttr(::new (S.Context) AttrType(S.Context, CI)); | 410 | 2.41k | } |
|
411 | | |
412 | | template <typename... DiagnosticArgs> |
413 | | static const Sema::SemaDiagnosticBuilder& |
414 | 4 | appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { |
415 | 4 | return Bldr; |
416 | 4 | } |
417 | | |
418 | | template <typename T, typename... DiagnosticArgs> |
419 | | static const Sema::SemaDiagnosticBuilder& |
420 | | appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, |
421 | 12 | DiagnosticArgs &&... ExtraArgs) { |
422 | 12 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), |
423 | 12 | std::forward<DiagnosticArgs>(ExtraArgs)...); |
424 | 12 | } SemaDeclAttr.cpp:clang::Sema::SemaDiagnosticBuilder const& appendDiagnostics<clang::ParsedAttr const&, int, clang::SourceRange>(clang::Sema::SemaDiagnosticBuilder const&, clang::ParsedAttr const&, int&&, clang::SourceRange&&) Line | Count | Source | 421 | 2 | DiagnosticArgs &&... ExtraArgs) { | 422 | 2 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), | 423 | 2 | std::forward<DiagnosticArgs>(ExtraArgs)...); | 424 | 2 | } |
SemaDeclAttr.cpp:clang::Sema::SemaDiagnosticBuilder const& appendDiagnostics<int, clang::SourceRange>(clang::Sema::SemaDiagnosticBuilder const&, int&&, clang::SourceRange&&) Line | Count | Source | 421 | 2 | DiagnosticArgs &&... ExtraArgs) { | 422 | 2 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), | 423 | 2 | std::forward<DiagnosticArgs>(ExtraArgs)...); | 424 | 2 | } |
SemaDeclAttr.cpp:clang::Sema::SemaDiagnosticBuilder const& appendDiagnostics<clang::SourceRange>(clang::Sema::SemaDiagnosticBuilder const&, clang::SourceRange&&) Line | Count | Source | 421 | 2 | DiagnosticArgs &&... ExtraArgs) { | 422 | 2 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), | 423 | 2 | std::forward<DiagnosticArgs>(ExtraArgs)...); | 424 | 2 | } |
SemaDeclAttr.cpp:clang::Sema::SemaDiagnosticBuilder const& appendDiagnostics<clang::SourceRange, char const (&) [12], int>(clang::Sema::SemaDiagnosticBuilder const&, clang::SourceRange&&, char const (&) [12], int&&) Line | Count | Source | 421 | 2 | DiagnosticArgs &&... ExtraArgs) { | 422 | 2 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), | 423 | 2 | std::forward<DiagnosticArgs>(ExtraArgs)...); | 424 | 2 | } |
SemaDeclAttr.cpp:clang::Sema::SemaDiagnosticBuilder const& appendDiagnostics<char const (&) [12], int>(clang::Sema::SemaDiagnosticBuilder const&, char const (&) [12], int&&) Line | Count | Source | 421 | 2 | DiagnosticArgs &&... ExtraArgs) { | 422 | 2 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), | 423 | 2 | std::forward<DiagnosticArgs>(ExtraArgs)...); | 424 | 2 | } |
SemaDeclAttr.cpp:clang::Sema::SemaDiagnosticBuilder const& appendDiagnostics<int>(clang::Sema::SemaDiagnosticBuilder const&, int&&) Line | Count | Source | 421 | 2 | DiagnosticArgs &&... ExtraArgs) { | 422 | 2 | return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), | 423 | 2 | std::forward<DiagnosticArgs>(ExtraArgs)...); | 424 | 2 | } |
|
425 | | |
426 | | /// Add an attribute {@code AttrType} to declaration {@code D}, provided that |
427 | | /// {@code PassesCheck} is true. |
428 | | /// Otherwise, emit diagnostic {@code DiagID}, passing in all parameters |
429 | | /// specified in {@code ExtraArgs}. |
430 | | template <typename AttrType, typename... DiagnosticArgs> |
431 | | static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, |
432 | | const AttributeCommonInfo &CI, |
433 | | bool PassesCheck, unsigned DiagID, |
434 | 2.93k | DiagnosticArgs &&... ExtraArgs) { |
435 | 2.93k | if (!PassesCheck) { |
436 | 4 | Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); |
437 | 4 | appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); |
438 | 4 | return; |
439 | 4 | } |
440 | 2.92k | handleSimpleAttribute<AttrType>(S, D, CI); |
441 | 2.92k | } SemaDeclAttr.cpp:void handleSimpleAttributeOrDiagnose<clang::OSReturnsRetainedOnZeroAttr, clang::ParsedAttr const&, int, clang::SourceRange>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, bool, unsigned int, clang::ParsedAttr const&, int&&, clang::SourceRange&&) Line | Count | Source | 434 | 4 | DiagnosticArgs &&... ExtraArgs) { | 435 | 4 | if (!PassesCheck) { | 436 | 1 | Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); | 437 | 1 | appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); | 438 | 1 | return; | 439 | 1 | } | 440 | 3 | handleSimpleAttribute<AttrType>(S, D, CI); | 441 | 3 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeOrDiagnose<clang::OSReturnsRetainedOnNonZeroAttr, clang::ParsedAttr const&, int, clang::SourceRange>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, bool, unsigned int, clang::ParsedAttr const&, int&&, clang::SourceRange&&) Line | Count | Source | 434 | 3 | DiagnosticArgs &&... ExtraArgs) { | 435 | 3 | if (!PassesCheck) { | 436 | 1 | Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); | 437 | 1 | appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); | 438 | 1 | return; | 439 | 1 | } | 440 | 2 | handleSimpleAttribute<AttrType>(S, D, CI); | 441 | 2 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeOrDiagnose<clang::OSConsumedAttr, clang::SourceRange, char const (&) [12], int>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, bool, unsigned int, clang::SourceRange&&, char const (&) [12], int&&) Line | Count | Source | 434 | 10 | DiagnosticArgs &&... ExtraArgs) { | 435 | 10 | if (!PassesCheck) { | 436 | 1 | Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); | 437 | 1 | appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); | 438 | 1 | return; | 439 | 1 | } | 440 | 9 | handleSimpleAttribute<AttrType>(S, D, CI); | 441 | 9 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeOrDiagnose<clang::NSConsumedAttr, clang::SourceRange, char const (&) [12], int>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, bool, unsigned int, clang::SourceRange&&, char const (&) [12], int&&) Line | Count | Source | 434 | 495 | DiagnosticArgs &&... ExtraArgs) { | 435 | 495 | if (!PassesCheck) { | 436 | 1 | Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); | 437 | 1 | appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); | 438 | 1 | return; | 439 | 1 | } | 440 | 494 | handleSimpleAttribute<AttrType>(S, D, CI); | 441 | 494 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeOrDiagnose<clang::CFConsumedAttr, clang::SourceRange, char const (&) [12], int>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, bool, unsigned int, clang::SourceRange&&, char const (&) [12], int&&) Line | Count | Source | 434 | 2.41k | DiagnosticArgs &&... ExtraArgs) { | 435 | 2.41k | if (!PassesCheck) { | 436 | 0 | Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); | 437 | 0 | appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); | 438 | 0 | return; | 439 | 0 | } | 440 | 2.41k | handleSimpleAttribute<AttrType>(S, D, CI); | 441 | 2.41k | } |
|
442 | | |
443 | | template <typename AttrType> |
444 | | static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, |
445 | 6.13k | const ParsedAttr &AL) { |
446 | 6.13k | handleSimpleAttribute<AttrType>(S, D, AL); |
447 | 6.13k | } SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::Mips16Attr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 8 | const ParsedAttr &AL) { | 446 | 8 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 8 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::MicroMipsAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 3 | const ParsedAttr &AL) { | 446 | 3 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 3 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::MipsLongCallAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 14 | const ParsedAttr &AL) { | 446 | 14 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::MipsShortCallAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 14 | const ParsedAttr &AL) { | 446 | 14 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CUDAHostAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 1.06k | const ParsedAttr &AL) { | 446 | 1.06k | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 1.06k | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CUDADeviceBuiltinSurfaceTypeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 10 | const ParsedAttr &AL) { | 446 | 10 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CUDADeviceBuiltinTextureTypeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 10 | const ParsedAttr &AL) { | 446 | 10 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::ColdAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 3.79k | const ParsedAttr &AL) { | 446 | 3.79k | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 3.79k | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::HotAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 14 | const ParsedAttr &AL) { | 446 | 14 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 14 | } |
Unexecuted instantiation: SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CFAuditedTransferAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CFUnknownTransferAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 1 | const ParsedAttr &AL) { | 446 | 1 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 1 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::SpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 25 | const ParsedAttr &AL) { | 446 | 25 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 25 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::NoSpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 25 | const ParsedAttr &AL) { | 446 | 25 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 25 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::NotTailCalledAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 667 | const ParsedAttr &AL) { | 446 | 667 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 667 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::DisableTailCallsAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 419 | const ParsedAttr &AL) { | 446 | 419 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 419 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::AlwaysDestroyAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 24 | const ParsedAttr &AL) { | 446 | 24 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 24 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::NoDestroyAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 445 | 38 | const ParsedAttr &AL) { | 446 | 38 | handleSimpleAttribute<AttrType>(S, D, AL); | 447 | 38 | } |
|
448 | | |
449 | | /// Applies the given attribute to the Decl so long as the Decl doesn't |
450 | | /// already have one of the given incompatible attributes. |
451 | | template <typename AttrType, typename IncompatibleAttrType, |
452 | | typename... IncompatibleAttrTypes> |
453 | | static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, |
454 | 6.16k | const ParsedAttr &AL) { |
455 | 6.16k | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) |
456 | 27 | return; |
457 | 6.14k | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, |
458 | 6.14k | AL); |
459 | 6.14k | } SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::Mips16Attr, clang::MicroMipsAttr, clang::MipsInterruptAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 11 | const ParsedAttr &AL) { | 455 | 11 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 1 | return; | 457 | 10 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 10 | AL); | 459 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::Mips16Attr, clang::MipsInterruptAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 10 | const ParsedAttr &AL) { | 455 | 10 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 8 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 8 | AL); | 459 | 8 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::MicroMipsAttr, clang::Mips16Attr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 5 | const ParsedAttr &AL) { | 455 | 5 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 3 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 3 | AL); | 459 | 3 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::MipsLongCallAttr, clang::MipsShortCallAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 16 | const ParsedAttr &AL) { | 455 | 16 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 14 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 14 | AL); | 459 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::MipsShortCallAttr, clang::MipsLongCallAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 16 | const ParsedAttr &AL) { | 455 | 16 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 14 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 14 | AL); | 459 | 14 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CUDAHostAttr, clang::CUDAGlobalAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 1.06k | const ParsedAttr &AL) { | 455 | 1.06k | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 1.06k | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 1.06k | AL); | 459 | 1.06k | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CUDADeviceBuiltinSurfaceTypeAttr, clang::CUDADeviceBuiltinTextureTypeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 10 | const ParsedAttr &AL) { | 455 | 10 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 0 | return; | 457 | 10 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 10 | AL); | 459 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CUDADeviceBuiltinTextureTypeAttr, clang::CUDADeviceBuiltinSurfaceTypeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 10 | const ParsedAttr &AL) { | 455 | 10 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 0 | return; | 457 | 10 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 10 | AL); | 459 | 10 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::ColdAttr, clang::HotAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 3.79k | const ParsedAttr &AL) { | 455 | 3.79k | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 1 | return; | 457 | 3.79k | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 3.79k | AL); | 459 | 3.79k | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::HotAttr, clang::ColdAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 15 | const ParsedAttr &AL) { | 455 | 15 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 1 | return; | 457 | 14 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 14 | AL); | 459 | 14 | } |
Unexecuted instantiation: SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CFAuditedTransferAttr, clang::CFUnknownTransferAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::CFUnknownTransferAttr, clang::CFAuditedTransferAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 1 | const ParsedAttr &AL) { | 455 | 1 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 0 | return; | 457 | 1 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 1 | AL); | 459 | 1 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::SpeculativeLoadHardeningAttr, clang::NoSpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 27 | const ParsedAttr &AL) { | 455 | 27 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 25 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 25 | AL); | 459 | 25 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::NoSpeculativeLoadHardeningAttr, clang::SpeculativeLoadHardeningAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 27 | const ParsedAttr &AL) { | 455 | 27 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 2 | return; | 457 | 25 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 25 | AL); | 459 | 25 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::NotTailCalledAttr, clang::AlwaysInlineAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 668 | const ParsedAttr &AL) { | 455 | 668 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 1 | return; | 457 | 667 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 667 | AL); | 459 | 667 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::DisableTailCallsAttr, clang::NakedAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 420 | const ParsedAttr &AL) { | 455 | 420 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 1 | return; | 457 | 419 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 419 | AL); | 459 | 419 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::AlwaysDestroyAttr, clang::NoDestroyAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 28 | const ParsedAttr &AL) { | 455 | 28 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 4 | return; | 457 | 24 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 24 | AL); | 459 | 24 | } |
SemaDeclAttr.cpp:void handleSimpleAttributeWithExclusions<clang::NoDestroyAttr, clang::AlwaysDestroyAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 454 | 42 | const ParsedAttr &AL) { | 455 | 42 | if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) | 456 | 4 | return; | 457 | 38 | handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, | 458 | 38 | AL); | 459 | 38 | } |
|
460 | | |
461 | | /// Check if the passed-in expression is of type int or bool. |
462 | 176 | static bool isIntOrBool(Expr *Exp) { |
463 | 176 | QualType QT = Exp->getType(); |
464 | 176 | return QT->isBooleanType() || QT->isIntegerType()120 ; |
465 | 176 | } |
466 | | |
467 | | |
468 | | // Check to see if the type is a smart pointer of some kind. We assume |
469 | | // it's a smart pointer if it defines both operator-> and operator*. |
470 | 2.77k | static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { |
471 | 2.77k | auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record, |
472 | 5.64k | OverloadedOperatorKind Op) { |
473 | 5.64k | DeclContextLookupResult Result = |
474 | 5.64k | Record->lookup(S.Context.DeclarationNames.getCXXOperatorName(Op)); |
475 | 5.64k | return !Result.empty(); |
476 | 5.64k | }; |
477 | | |
478 | 2.77k | const RecordDecl *Record = RT->getDecl(); |
479 | 2.77k | bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star); |
480 | 2.77k | bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow); |
481 | 2.77k | if (foundStarOperator && foundArrowOperator46 ) |
482 | 46 | return true; |
483 | | |
484 | 2.73k | const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record); |
485 | 2.73k | if (!CXXRecord) |
486 | 21 | return false; |
487 | | |
488 | 2.70k | for (auto BaseSpecifier : CXXRecord->bases()) { |
489 | 44 | if (!foundStarOperator) |
490 | 44 | foundStarOperator = IsOverloadedOperatorPresent( |
491 | 44 | BaseSpecifier.getType()->getAsRecordDecl(), OO_Star); |
492 | 44 | if (!foundArrowOperator) |
493 | 44 | foundArrowOperator = IsOverloadedOperatorPresent( |
494 | 44 | BaseSpecifier.getType()->getAsRecordDecl(), OO_Arrow); |
495 | 44 | } |
496 | | |
497 | 2.70k | if (foundStarOperator && foundArrowOperator16 ) |
498 | 16 | return true; |
499 | | |
500 | 2.69k | return false; |
501 | 2.69k | } |
502 | | |
503 | | /// Check if passed in Decl is a pointer type. |
504 | | /// Note that this function may produce an error message. |
505 | | /// \return true if the Decl is a pointer type; false otherwise |
506 | | static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, |
507 | 153 | const ParsedAttr &AL) { |
508 | 153 | const auto *VD = cast<ValueDecl>(D); |
509 | 153 | QualType QT = VD->getType(); |
510 | 153 | if (QT->isAnyPointerType()) |
511 | 114 | return true; |
512 | | |
513 | 39 | if (const auto *RT = QT->getAs<RecordType>()) { |
514 | | // If it's an incomplete type, it could be a smart pointer; skip it. |
515 | | // (We don't want to force template instantiation if we can avoid it, |
516 | | // since that would alter the order in which templates are instantiated.) |
517 | 22 | if (RT->isIncompleteType()) |
518 | 3 | return true; |
519 | | |
520 | 19 | if (threadSafetyCheckIsSmartPointer(S, RT)) |
521 | 19 | return true; |
522 | 17 | } |
523 | | |
524 | 17 | S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) << AL << QT; |
525 | 17 | return false; |
526 | 17 | } |
527 | | |
528 | | /// Checks that the passed in QualType either is of RecordType or points |
529 | | /// to RecordType. Returns the relevant RecordType, null if it does not exit. |
530 | 5.56k | static const RecordType *getRecordType(QualType QT) { |
531 | 5.56k | if (const auto *RT = QT->getAs<RecordType>()) |
532 | 4.50k | return RT; |
533 | | |
534 | | // Now check if we point to record type. |
535 | 1.05k | if (const auto *PT = QT->getAs<PointerType>()) |
536 | 804 | return PT->getPointeeType()->getAs<RecordType>(); |
537 | | |
538 | 253 | return nullptr; |
539 | 253 | } |
540 | | |
541 | | template <typename AttrType> |
542 | 3.25k | static bool checkRecordDeclForAttr(const RecordDecl *RD) { |
543 | | // Check if the record itself has the attribute. |
544 | 3.25k | if (RD->hasAttr<AttrType>()) |
545 | 2.92k | return true; |
546 | | |
547 | | // Else check if any base classes have the attribute. |
548 | 325 | if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { |
549 | 323 | CXXBasePaths BPaths(false, false); |
550 | 323 | if (CRD->lookupInBases( |
551 | 49 | [](const CXXBaseSpecifier *BS, CXXBasePath &) { |
552 | 49 | const auto &Ty = *BS->getType(); |
553 | | // If it's type-dependent, we assume it could have the attribute. |
554 | 49 | if (Ty.isDependentType()) |
555 | 3 | return true; |
556 | 46 | return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>(); |
557 | 46 | }, SemaDeclAttr.cpp:bool checkRecordDeclForAttr<clang::CapabilityAttr>(clang::RecordDecl const*)::'lambda'(clang::CXXBaseSpecifier const*, clang::CXXBasePath&)::operator()(clang::CXXBaseSpecifier const*, clang::CXXBasePath&) const Line | Count | Source | 551 | 43 | [](const CXXBaseSpecifier *BS, CXXBasePath &) { | 552 | 43 | const auto &Ty = *BS->getType(); | 553 | | // If it's type-dependent, we assume it could have the attribute. | 554 | 43 | if (Ty.isDependentType()) | 555 | 3 | return true; | 556 | 40 | return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>(); | 557 | 40 | }, |
SemaDeclAttr.cpp:bool checkRecordDeclForAttr<clang::ScopedLockableAttr>(clang::RecordDecl const*)::'lambda'(clang::CXXBaseSpecifier const*, clang::CXXBasePath&)::operator()(clang::CXXBaseSpecifier const*, clang::CXXBasePath&) const Line | Count | Source | 551 | 6 | [](const CXXBaseSpecifier *BS, CXXBasePath &) { | 552 | 6 | const auto &Ty = *BS->getType(); | 553 | | // If it's type-dependent, we assume it could have the attribute. | 554 | 6 | if (Ty.isDependentType()) | 555 | 0 | return true; | 556 | 6 | return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>(); | 557 | 6 | }, |
|
558 | 323 | BPaths, true)) |
559 | 22 | return true; |
560 | 303 | } |
561 | 303 | return false; |
562 | 303 | } SemaDeclAttr.cpp:bool checkRecordDeclForAttr<clang::CapabilityAttr>(clang::RecordDecl const*) Line | Count | Source | 542 | 3.08k | static bool checkRecordDeclForAttr(const RecordDecl *RD) { | 543 | | // Check if the record itself has the attribute. | 544 | 3.08k | if (RD->hasAttr<AttrType>()) | 545 | 2.79k | return true; | 546 | | | 547 | | // Else check if any base classes have the attribute. | 548 | 297 | if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { | 549 | 295 | CXXBasePaths BPaths(false, false); | 550 | 295 | if (CRD->lookupInBases( | 551 | 295 | [](const CXXBaseSpecifier *BS, CXXBasePath &) { | 552 | 295 | const auto &Ty = *BS->getType(); | 553 | | // If it's type-dependent, we assume it could have the attribute. | 554 | 295 | if (Ty.isDependentType()) | 555 | 295 | return true; | 556 | 295 | return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>(); | 557 | 295 | }, | 558 | 295 | BPaths, true)) | 559 | 19 | return true; | 560 | 278 | } | 561 | 278 | return false; | 562 | 278 | } |
SemaDeclAttr.cpp:bool checkRecordDeclForAttr<clang::ScopedLockableAttr>(clang::RecordDecl const*) Line | Count | Source | 542 | 167 | static bool checkRecordDeclForAttr(const RecordDecl *RD) { | 543 | | // Check if the record itself has the attribute. | 544 | 167 | if (RD->hasAttr<AttrType>()) | 545 | 139 | return true; | 546 | | | 547 | | // Else check if any base classes have the attribute. | 548 | 28 | if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { | 549 | 28 | CXXBasePaths BPaths(false, false); | 550 | 28 | if (CRD->lookupInBases( | 551 | 28 | [](const CXXBaseSpecifier *BS, CXXBasePath &) { | 552 | 28 | const auto &Ty = *BS->getType(); | 553 | | // If it's type-dependent, we assume it could have the attribute. | 554 | 28 | if (Ty.isDependentType()) | 555 | 28 | return true; | 556 | 28 | return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>(); | 557 | 28 | }, | 558 | 28 | BPaths, true)) | 559 | 3 | return true; | 560 | 25 | } | 561 | 25 | return false; | 562 | 25 | } |
|
563 | | |
564 | 2.92k | static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { |
565 | 2.92k | const RecordType *RT = getRecordType(Ty); |
566 | | |
567 | 2.92k | if (!RT) |
568 | 172 | return false; |
569 | | |
570 | | // Don't check for the capability if the class hasn't been defined yet. |
571 | 2.75k | if (RT->isIncompleteType()) |
572 | 0 | return true; |
573 | | |
574 | | // Allow smart pointers to be used as capability objects. |
575 | | // FIXME -- Check the type that the smart pointer points to. |
576 | 2.75k | if (threadSafetyCheckIsSmartPointer(S, RT)) |
577 | 43 | return true; |
578 | | |
579 | 2.71k | return checkRecordDeclForAttr<CapabilityAttr>(RT->getDecl()); |
580 | 2.71k | } |
581 | | |
582 | 2.98k | static bool checkTypedefTypeForCapability(QualType Ty) { |
583 | 2.98k | const auto *TD = Ty->getAs<TypedefType>(); |
584 | 2.98k | if (!TD) |
585 | 2.92k | return false; |
586 | | |
587 | 60 | TypedefNameDecl *TN = TD->getDecl(); |
588 | 60 | if (!TN) |
589 | 0 | return false; |
590 | | |
591 | 60 | return TN->hasAttr<CapabilityAttr>(); |
592 | 60 | } |
593 | | |
594 | 2.98k | static bool typeHasCapability(Sema &S, QualType Ty) { |
595 | 2.98k | if (checkTypedefTypeForCapability(Ty)) |
596 | 60 | return true; |
597 | | |
598 | 2.92k | if (checkRecordTypeForCapability(S, Ty)) |
599 | 2.64k | return true; |
600 | | |
601 | 283 | return false; |
602 | 283 | } |
603 | | |
604 | 251 | static bool isCapabilityExpr(Sema &S, const Expr *Ex) { |
605 | | // Capability expressions are simple expressions involving the boolean logic |
606 | | // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once |
607 | | // a DeclRefExpr is found, its type should be checked to determine whether it |
608 | | // is a capability or not. |
609 | | |
610 | 251 | if (const auto *E = dyn_cast<CastExpr>(Ex)) |
611 | 50 | return isCapabilityExpr(S, E->getSubExpr()); |
612 | 201 | else if (const auto *E = dyn_cast<ParenExpr>(Ex)) |
613 | 1 | return isCapabilityExpr(S, E->getSubExpr()); |
614 | 200 | else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) { |
615 | 38 | if (E->getOpcode() == UO_LNot || E->getOpcode() == UO_AddrOf12 || |
616 | 3 | E->getOpcode() == UO_Deref) |
617 | 38 | return isCapabilityExpr(S, E->getSubExpr()); |
618 | 0 | return false; |
619 | 162 | } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) { |
620 | 5 | if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr2 ) |
621 | 5 | return isCapabilityExpr(S, E->getLHS()) && |
622 | 5 | isCapabilityExpr(S, E->getRHS()); |
623 | 0 | return false; |
624 | 0 | } |
625 | | |
626 | 157 | return typeHasCapability(S, Ex->getType()); |
627 | 157 | } |
628 | | |
629 | | /// Checks that all attribute arguments, starting from Sidx, resolve to |
630 | | /// a capability object. |
631 | | /// \param Sidx The attribute argument index to start checking with. |
632 | | /// \param ParamIdxOk Whether an argument can be indexing into a function |
633 | | /// parameter list. |
634 | | static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, |
635 | | const ParsedAttr &AL, |
636 | | SmallVectorImpl<Expr *> &Args, |
637 | | unsigned Sidx = 0, |
638 | 3.01k | bool ParamIdxOk = false) { |
639 | 3.01k | if (Sidx == AL.getNumArgs()) { |
640 | | // If we don't have any capability arguments, the attribute implicitly |
641 | | // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're |
642 | | // a non-static method, and that the class is a (scoped) capability. |
643 | 418 | const auto *MD = dyn_cast<const CXXMethodDecl>(D); |
644 | 418 | if (MD && !MD->isStatic()373 ) { |
645 | 373 | const CXXRecordDecl *RD = MD->getParent(); |
646 | | // FIXME -- need to check this again on template instantiation |
647 | 373 | if (!checkRecordDeclForAttr<CapabilityAttr>(RD) && |
648 | 167 | !checkRecordDeclForAttr<ScopedLockableAttr>(RD)) |
649 | 25 | S.Diag(AL.getLoc(), |
650 | 25 | diag::warn_thread_attribute_not_on_capability_member) |
651 | 25 | << AL << MD->getParent(); |
652 | 45 | } else { |
653 | 45 | S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member) |
654 | 45 | << AL; |
655 | 45 | } |
656 | 418 | } |
657 | | |
658 | 5.80k | for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx2.79k ) { |
659 | 2.79k | Expr *ArgExp = AL.getArgAsExpr(Idx); |
660 | | |
661 | 2.79k | if (ArgExp->isTypeDependent()) { |
662 | | // FIXME -- need to check this again on template instantiation |
663 | 54 | Args.push_back(ArgExp); |
664 | 54 | continue; |
665 | 54 | } |
666 | | |
667 | 2.73k | if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) { |
668 | 104 | if (StrLit->getLength() == 0 || |
669 | 70 | (StrLit->isAscii() && StrLit->getString() == StringRef("*")67 )) { |
670 | | // Pass empty strings to the analyzer without warnings. |
671 | | // Treat "*" as the universal lock. |
672 | 62 | Args.push_back(ArgExp); |
673 | 62 | continue; |
674 | 62 | } |
675 | | |
676 | | // We allow constant strings to be used as a placeholder for expressions |
677 | | // that are not valid C++ syntax, but warn that they are ignored. |
678 | 42 | S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL; |
679 | 42 | Args.push_back(ArgExp); |
680 | 42 | continue; |
681 | 42 | } |
682 | | |
683 | 2.63k | QualType ArgTy = ArgExp->getType(); |
684 | | |
685 | | // A pointer to member expression of the form &MyClass::mu is treated |
686 | | // specially -- we need to look at the type of the member. |
687 | 2.63k | if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp)) |
688 | 140 | if (UOp->getOpcode() == UO_AddrOf) |
689 | 76 | if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) |
690 | 76 | if (DRE->getDecl()->isCXXInstanceMember()) |
691 | 37 | ArgTy = DRE->getDecl()->getType(); |
692 | | |
693 | | // First see if we can just cast to record type, or pointer to record type. |
694 | 2.63k | const RecordType *RT = getRecordType(ArgTy); |
695 | | |
696 | | // Now check if we index into a record type function param. |
697 | 2.63k | if(!RT && ParamIdxOk198 ) { |
698 | 89 | const auto *FD = dyn_cast<FunctionDecl>(D); |
699 | 89 | const auto *IL = dyn_cast<IntegerLiteral>(ArgExp); |
700 | 89 | if(FD && IL) { |
701 | 63 | unsigned int NumParams = FD->getNumParams(); |
702 | 63 | llvm::APInt ArgValue = IL->getValue(); |
703 | 63 | uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); |
704 | 63 | uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; |
705 | 63 | if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams36 ) { |
706 | 36 | S.Diag(AL.getLoc(), |
707 | 36 | diag::err_attribute_argument_out_of_bounds_extra_info) |
708 | 36 | << AL << Idx + 1 << NumParams; |
709 | 36 | continue; |
710 | 36 | } |
711 | 27 | ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); |
712 | 27 | } |
713 | 89 | } |
714 | | |
715 | | // If the type does not have a capability, see if the components of the |
716 | | // expression have capabilities. This allows for writing C code where the |
717 | | // capability may be on the type, and the expression is a capability |
718 | | // boolean logic expression. Eg) requires_capability(A || B && !C) |
719 | 2.59k | if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)152 ) |
720 | 125 | S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable) |
721 | 125 | << AL << ArgTy; |
722 | | |
723 | 2.59k | Args.push_back(ArgExp); |
724 | 2.59k | } |
725 | 3.01k | } |
726 | | |
727 | | //===----------------------------------------------------------------------===// |
728 | | // Attribute Implementations |
729 | | //===----------------------------------------------------------------------===// |
730 | | |
731 | 21 | static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
732 | 21 | if (!threadSafetyCheckIsPointer(S, D, AL)) |
733 | 10 | return; |
734 | | |
735 | 11 | D->addAttr(::new (S.Context) PtGuardedVarAttr(S.Context, AL)); |
736 | 11 | } |
737 | | |
738 | | static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, |
739 | 682 | Expr *&Arg) { |
740 | 682 | SmallVector<Expr *, 1> Args; |
741 | | // check that all arguments are lockable objects |
742 | 682 | checkAttrArgsAreCapabilityObjs(S, D, AL, Args); |
743 | 682 | unsigned Size = Args.size(); |
744 | 682 | if (Size != 1) |
745 | 0 | return false; |
746 | | |
747 | 682 | Arg = Args[0]; |
748 | | |
749 | 682 | return true; |
750 | 682 | } |
751 | | |
752 | 550 | static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
753 | 550 | Expr *Arg = nullptr; |
754 | 550 | if (!checkGuardedByAttrCommon(S, D, AL, Arg)) |
755 | 0 | return; |
756 | | |
757 | 550 | D->addAttr(::new (S.Context) GuardedByAttr(S.Context, AL, Arg)); |
758 | 550 | } |
759 | | |
760 | 132 | static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
761 | 132 | Expr *Arg = nullptr; |
762 | 132 | if (!checkGuardedByAttrCommon(S, D, AL, Arg)) |
763 | 0 | return; |
764 | | |
765 | 132 | if (!threadSafetyCheckIsPointer(S, D, AL)) |
766 | 7 | return; |
767 | | |
768 | 125 | D->addAttr(::new (S.Context) PtGuardedByAttr(S.Context, AL, Arg)); |
769 | 125 | } |
770 | | |
771 | | static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, |
772 | 246 | SmallVectorImpl<Expr *> &Args) { |
773 | 246 | if (!checkAttributeAtLeastNumArgs(S, AL, 1)) |
774 | 12 | return false; |
775 | | |
776 | | // Check that this attribute only applies to lockable types. |
777 | 234 | QualType QT = cast<ValueDecl>(D)->getType(); |
778 | 234 | if (!QT->isDependentType() && !typeHasCapability(S, QT)) { |
779 | 6 | S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) << AL; |
780 | 6 | return false; |
781 | 6 | } |
782 | | |
783 | | // Check that all arguments are lockable objects. |
784 | 228 | checkAttrArgsAreCapabilityObjs(S, D, AL, Args); |
785 | 228 | if (Args.empty()) |
786 | 0 | return false; |
787 | | |
788 | 228 | return true; |
789 | 228 | } |
790 | | |
791 | 143 | static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
792 | 143 | SmallVector<Expr *, 1> Args; |
793 | 143 | if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) |
794 | 9 | return; |
795 | | |
796 | 134 | Expr **StartArg = &Args[0]; |
797 | 134 | D->addAttr(::new (S.Context) |
798 | 134 | AcquiredAfterAttr(S.Context, AL, StartArg, Args.size())); |
799 | 134 | } |
800 | | |
801 | 103 | static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
802 | 103 | SmallVector<Expr *, 1> Args; |
803 | 103 | if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) |
804 | 9 | return; |
805 | | |
806 | 94 | Expr **StartArg = &Args[0]; |
807 | 94 | D->addAttr(::new (S.Context) |
808 | 94 | AcquiredBeforeAttr(S.Context, AL, StartArg, Args.size())); |
809 | 94 | } |
810 | | |
811 | | static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, |
812 | 551 | SmallVectorImpl<Expr *> &Args) { |
813 | | // zero or more arguments ok |
814 | | // check that all arguments are lockable objects |
815 | 551 | checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, /*ParamIdxOk=*/true); |
816 | | |
817 | 551 | return true; |
818 | 551 | } |
819 | | |
820 | 13 | static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
821 | 13 | SmallVector<Expr *, 1> Args; |
822 | 13 | if (!checkLockFunAttrCommon(S, D, AL, Args)) |
823 | 0 | return; |
824 | | |
825 | 13 | unsigned Size = Args.size(); |
826 | 7 | Expr **StartArg = Size == 0 ? nullptr : &Args[0]6 ; |
827 | 13 | D->addAttr(::new (S.Context) |
828 | 13 | AssertSharedLockAttr(S.Context, AL, StartArg, Size)); |
829 | 13 | } |
830 | | |
831 | | static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, |
832 | 15 | const ParsedAttr &AL) { |
833 | 15 | SmallVector<Expr *, 1> Args; |
834 | 15 | if (!checkLockFunAttrCommon(S, D, AL, Args)) |
835 | 0 | return; |
836 | | |
837 | 15 | unsigned Size = Args.size(); |
838 | 8 | Expr **StartArg = Size == 0 ? nullptr7 : &Args[0]; |
839 | 15 | D->addAttr(::new (S.Context) |
840 | 15 | AssertExclusiveLockAttr(S.Context, AL, StartArg, Size)); |
841 | 15 | } |
842 | | |
843 | | /// Checks to be sure that the given parameter number is in bounds, and |
844 | | /// is an integral type. Will emit appropriate diagnostics if this returns |
845 | | /// false. |
846 | | /// |
847 | | /// AttrArgNo is used to actually retrieve the argument, so it's base-0. |
848 | | template <typename AttrInfo> |
849 | | static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, |
850 | 6.12k | const AttrInfo &AI, unsigned AttrArgNo) { |
851 | 6.12k | assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument"); |
852 | 6.12k | Expr *AttrArg = AI.getArgAsExpr(AttrArgNo); |
853 | 6.12k | ParamIdx Idx; |
854 | 6.12k | if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg, |
855 | 6.12k | Idx)) |
856 | 6 | return false; |
857 | | |
858 | 6.11k | const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex()); |
859 | 6.11k | if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()1 ) { |
860 | 1 | SourceLocation SrcLoc = AttrArg->getBeginLoc(); |
861 | 1 | S.Diag(SrcLoc, diag::err_attribute_integers_only) |
862 | 1 | << AI << Param->getSourceRange(); |
863 | 1 | return false; |
864 | 1 | } |
865 | 6.11k | return true; |
866 | 6.11k | } |
867 | | |
868 | 5.15k | static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
869 | 5.15k | if (!checkAttributeAtLeastNumArgs(S, AL, 1) || |
870 | 5.15k | !checkAttributeAtMostNumArgs(S, AL, 2)) |
871 | 0 | return; |
872 | | |
873 | 5.15k | const auto *FD = cast<FunctionDecl>(D); |
874 | 5.15k | if (!FD->getReturnType()->isPointerType()) { |
875 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) << AL; |
876 | 1 | return; |
877 | 1 | } |
878 | | |
879 | 5.14k | const Expr *SizeExpr = AL.getArgAsExpr(0); |
880 | 5.14k | int SizeArgNoVal; |
881 | | // Parameter indices are 1-indexed, hence Index=1 |
882 | 5.14k | if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Idx=*/1)) |
883 | 2 | return; |
884 | 5.14k | if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0)) |
885 | 5 | return; |
886 | 5.14k | ParamIdx SizeArgNo(SizeArgNoVal, D); |
887 | | |
888 | 5.14k | ParamIdx NumberArgNo; |
889 | 5.14k | if (AL.getNumArgs() == 2) { |
890 | 976 | const Expr *NumberExpr = AL.getArgAsExpr(1); |
891 | 976 | int Val; |
892 | | // Parameter indices are 1-based, hence Index=2 |
893 | 976 | if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Idx=*/2)) |
894 | 1 | return; |
895 | 975 | if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1)) |
896 | 2 | return; |
897 | 973 | NumberArgNo = ParamIdx(Val, D); |
898 | 973 | } |
899 | | |
900 | 5.13k | D->addAttr(::new (S.Context) |
901 | 5.13k | AllocSizeAttr(S.Context, AL, SizeArgNo, NumberArgNo)); |
902 | 5.13k | } |
903 | | |
904 | | static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, |
905 | 176 | SmallVectorImpl<Expr *> &Args) { |
906 | 176 | if (!checkAttributeAtLeastNumArgs(S, AL, 1)) |
907 | 0 | return false; |
908 | | |
909 | 176 | if (!isIntOrBool(AL.getArgAsExpr(0))) { |
910 | 18 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
911 | 18 | << AL << 1 << AANT_ArgumentIntOrBool; |
912 | 18 | return false; |
913 | 18 | } |
914 | | |
915 | | // check that all arguments are lockable objects |
916 | 158 | checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1); |
917 | | |
918 | 158 | return true; |
919 | 158 | } |
920 | | |
921 | | static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D, |
922 | 70 | const ParsedAttr &AL) { |
923 | 70 | SmallVector<Expr*, 2> Args; |
924 | 70 | if (!checkTryLockFunAttrCommon(S, D, AL, Args)) |
925 | 9 | return; |
926 | | |
927 | 61 | D->addAttr(::new (S.Context) SharedTrylockFunctionAttr( |
928 | 61 | S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size())); |
929 | 61 | } |
930 | | |
931 | | static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, |
932 | 78 | const ParsedAttr &AL) { |
933 | 78 | SmallVector<Expr*, 2> Args; |
934 | 78 | if (!checkTryLockFunAttrCommon(S, D, AL, Args)) |
935 | 9 | return; |
936 | | |
937 | 69 | D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr( |
938 | 69 | S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size())); |
939 | 69 | } |
940 | | |
941 | 80 | static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
942 | | // check that the argument is lockable object |
943 | 80 | SmallVector<Expr*, 1> Args; |
944 | 80 | checkAttrArgsAreCapabilityObjs(S, D, AL, Args); |
945 | 80 | unsigned Size = Args.size(); |
946 | 80 | if (Size == 0) |
947 | 0 | return; |
948 | | |
949 | 80 | D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0])); |
950 | 80 | } |
951 | | |
952 | 142 | static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
953 | 142 | if (!checkAttributeAtLeastNumArgs(S, AL, 1)) |
954 | 3 | return; |
955 | | |
956 | | // check that all arguments are lockable objects |
957 | 139 | SmallVector<Expr*, 1> Args; |
958 | 139 | checkAttrArgsAreCapabilityObjs(S, D, AL, Args); |
959 | 139 | unsigned Size = Args.size(); |
960 | 139 | if (Size == 0) |
961 | 0 | return; |
962 | 139 | Expr **StartArg = &Args[0]; |
963 | | |
964 | 139 | D->addAttr(::new (S.Context) |
965 | 139 | LocksExcludedAttr(S.Context, AL, StartArg, Size)); |
966 | 139 | } |
967 | | |
968 | | static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL, |
969 | 18.2k | Expr *&Cond, StringRef &Msg) { |
970 | 18.2k | Cond = AL.getArgAsExpr(0); |
971 | 18.2k | if (!Cond->isTypeDependent()) { |
972 | 18.2k | ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); |
973 | 18.2k | if (Converted.isInvalid()) |
974 | 0 | return false; |
975 | 18.2k | Cond = Converted.get(); |
976 | 18.2k | } |
977 | | |
978 | 18.2k | if (!S.checkStringLiteralArgumentAttr(AL, 1, Msg)) |
979 | 2 | return false; |
980 | | |
981 | 18.2k | if (Msg.empty()) |
982 | 9.22k | Msg = "<no message provided>"; |
983 | | |
984 | 18.2k | SmallVector<PartialDiagnosticAt, 8> Diags; |
985 | 18.2k | if (isa<FunctionDecl>(D) && !Cond->isValueDependent()18.2k && |
986 | 18.1k | !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), |
987 | 3 | Diags)) { |
988 | 3 | S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) << AL; |
989 | 3 | for (const PartialDiagnosticAt &PDiag : Diags) |
990 | 3 | S.Diag(PDiag.first, PDiag.second); |
991 | 3 | return false; |
992 | 3 | } |
993 | 18.2k | return true; |
994 | 18.2k | } |
995 | | |
996 | 10.8k | static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
997 | 10.8k | S.Diag(AL.getLoc(), diag::ext_clang_enable_if); |
998 | | |
999 | 10.8k | Expr *Cond; |
1000 | 10.8k | StringRef Msg; |
1001 | 10.8k | if (checkFunctionConditionAttr(S, D, AL, Cond, Msg)) |
1002 | 10.8k | D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg)); |
1003 | 10.8k | } |
1004 | | |
1005 | | namespace { |
1006 | | /// Determines if a given Expr references any of the given function's |
1007 | | /// ParmVarDecls, or the function's implicit `this` parameter (if applicable). |
1008 | | class ArgumentDependenceChecker |
1009 | | : public RecursiveASTVisitor<ArgumentDependenceChecker> { |
1010 | | #ifndef NDEBUG |
1011 | | const CXXRecordDecl *ClassType; |
1012 | | #endif |
1013 | | llvm::SmallPtrSet<const ParmVarDecl *, 16> Parms; |
1014 | | bool Result; |
1015 | | |
1016 | | public: |
1017 | 7.43k | ArgumentDependenceChecker(const FunctionDecl *FD) { |
1018 | 7.43k | #ifndef NDEBUG |
1019 | 7.43k | if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) |
1020 | 3.28k | ClassType = MD->getParent(); |
1021 | 4.14k | else |
1022 | 4.14k | ClassType = nullptr; |
1023 | 7.43k | #endif |
1024 | 7.43k | Parms.insert(FD->param_begin(), FD->param_end()); |
1025 | 7.43k | } |
1026 | | |
1027 | 7.43k | bool referencesArgs(Expr *E) { |
1028 | 7.43k | Result = false; |
1029 | 7.43k | TraverseStmt(E); |
1030 | 7.43k | return Result; |
1031 | 7.43k | } |
1032 | | |
1033 | 27 | bool VisitCXXThisExpr(CXXThisExpr *E) { |
1034 | 27 | assert(E->getType()->getPointeeCXXRecordDecl() == ClassType && |
1035 | 27 | "`this` doesn't refer to the enclosing class?"); |
1036 | 27 | Result = true; |
1037 | 27 | return false; |
1038 | 27 | } |
1039 | | |
1040 | 7.33k | bool VisitDeclRefExpr(DeclRefExpr *DRE) { |
1041 | 7.33k | if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) |
1042 | 7.32k | if (Parms.count(PVD)) { |
1043 | 7.32k | Result = true; |
1044 | 7.32k | return false; |
1045 | 7.32k | } |
1046 | 12 | return true; |
1047 | 12 | } |
1048 | | }; |
1049 | | } |
1050 | | |
1051 | 7.43k | static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1052 | 7.43k | S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if); |
1053 | | |
1054 | 7.43k | Expr *Cond; |
1055 | 7.43k | StringRef Msg; |
1056 | 7.43k | if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg)) |
1057 | 3 | return; |
1058 | | |
1059 | 7.43k | StringRef DiagTypeStr; |
1060 | 7.43k | if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr)) |
1061 | 0 | return; |
1062 | | |
1063 | 7.43k | DiagnoseIfAttr::DiagnosticType DiagType; |
1064 | 7.43k | if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) { |
1065 | 3 | S.Diag(AL.getArgAsExpr(2)->getBeginLoc(), |
1066 | 3 | diag::err_diagnose_if_invalid_diagnostic_type); |
1067 | 3 | return; |
1068 | 3 | } |
1069 | | |
1070 | 7.43k | bool ArgDependent = false; |
1071 | 7.43k | if (const auto *FD = dyn_cast<FunctionDecl>(D)) |
1072 | 7.43k | ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); |
1073 | 7.43k | D->addAttr(::new (S.Context) DiagnoseIfAttr( |
1074 | 7.43k | S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D))); |
1075 | 7.43k | } |
1076 | | |
1077 | 31 | static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1078 | 31 | static constexpr const StringRef kWildcard = "*"; |
1079 | | |
1080 | 31 | llvm::SmallVector<StringRef, 16> Names; |
1081 | 31 | bool HasWildcard = false; |
1082 | | |
1083 | 41 | const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) { |
1084 | 41 | if (Name == kWildcard) |
1085 | 12 | HasWildcard = true; |
1086 | 41 | Names.push_back(Name); |
1087 | 41 | }; |
1088 | | |
1089 | | // Add previously defined attributes. |
1090 | 31 | if (const auto *NBA = D->getAttr<NoBuiltinAttr>()) |
1091 | 8 | for (StringRef BuiltinName : NBA->builtinNames()) |
1092 | 8 | AddBuiltinName(BuiltinName); |
1093 | | |
1094 | | // Add current attributes. |
1095 | 31 | if (AL.getNumArgs() == 0) |
1096 | 10 | AddBuiltinName(kWildcard); |
1097 | 21 | else |
1098 | 45 | for (unsigned I = 0, E = AL.getNumArgs(); 21 I != E; ++I24 ) { |
1099 | 24 | StringRef BuiltinName; |
1100 | 24 | SourceLocation LiteralLoc; |
1101 | 24 | if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc)) |
1102 | 0 | return; |
1103 | | |
1104 | 24 | if (Builtin::Context::isBuiltinFunc(BuiltinName)) |
1105 | 23 | AddBuiltinName(BuiltinName); |
1106 | 1 | else |
1107 | 1 | S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name) |
1108 | 1 | << BuiltinName << AL; |
1109 | 24 | } |
1110 | | |
1111 | | // Repeating the same attribute is fine. |
1112 | 31 | llvm::sort(Names); |
1113 | 31 | Names.erase(std::unique(Names.begin(), Names.end()), Names.end()); |
1114 | | |
1115 | | // Empty no_builtin must be on its own. |
1116 | 31 | if (HasWildcard && Names.size() > 111 ) |
1117 | 1 | S.Diag(D->getLocation(), |
1118 | 1 | diag::err_attribute_no_builtin_wildcard_or_builtin_name) |
1119 | 1 | << AL; |
1120 | | |
1121 | 31 | if (D->hasAttr<NoBuiltinAttr>()) |
1122 | 8 | D->dropAttr<NoBuiltinAttr>(); |
1123 | 31 | D->addAttr(::new (S.Context) |
1124 | 31 | NoBuiltinAttr(S.Context, AL, Names.data(), Names.size())); |
1125 | 31 | } |
1126 | | |
1127 | 134 | static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1128 | 134 | if (D->hasAttr<PassObjectSizeAttr>()) { |
1129 | 1 | S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL; |
1130 | 1 | return; |
1131 | 1 | } |
1132 | | |
1133 | 133 | Expr *E = AL.getArgAsExpr(0); |
1134 | 133 | uint32_t Type; |
1135 | 133 | if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1)) |
1136 | 2 | return; |
1137 | | |
1138 | | // pass_object_size's argument is passed in as the second argument of |
1139 | | // __builtin_object_size. So, it has the same constraints as that second |
1140 | | // argument; namely, it must be in the range [0, 3]. |
1141 | 131 | if (Type > 3) { |
1142 | 2 | S.Diag(E->getBeginLoc(), diag::err_attribute_argument_out_of_range) |
1143 | 2 | << AL << 0 << 3 << E->getSourceRange(); |
1144 | 2 | return; |
1145 | 2 | } |
1146 | | |
1147 | | // pass_object_size is only supported on constant pointer parameters; as a |
1148 | | // kindness to users, we allow the parameter to be non-const for declarations. |
1149 | | // At this point, we have no clue if `D` belongs to a function declaration or |
1150 | | // definition, so we defer the constness check until later. |
1151 | 129 | if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { |
1152 | 3 | S.Diag(D->getBeginLoc(), diag::err_attribute_pointers_only) << AL << 1; |
1153 | 3 | return; |
1154 | 3 | } |
1155 | | |
1156 | 126 | D->addAttr(::new (S.Context) PassObjectSizeAttr(S.Context, AL, (int)Type)); |
1157 | 126 | } |
1158 | | |
1159 | 7 | static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1160 | 7 | ConsumableAttr::ConsumedState DefaultState; |
1161 | | |
1162 | 7 | if (AL.isArgIdent(0)) { |
1163 | 6 | IdentifierLoc *IL = AL.getArgAsIdent(0); |
1164 | 6 | if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(), |
1165 | 0 | DefaultState)) { |
1166 | 0 | S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL |
1167 | 0 | << IL->Ident; |
1168 | 0 | return; |
1169 | 0 | } |
1170 | 1 | } else { |
1171 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_argument_type) |
1172 | 1 | << AL << AANT_ArgumentIdentifier; |
1173 | 1 | return; |
1174 | 1 | } |
1175 | | |
1176 | 6 | D->addAttr(::new (S.Context) ConsumableAttr(S.Context, AL, DefaultState)); |
1177 | 6 | } |
1178 | | |
1179 | | static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, |
1180 | 31 | const ParsedAttr &AL) { |
1181 | 31 | QualType ThisType = MD->getThisType()->getPointeeType(); |
1182 | | |
1183 | 31 | if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { |
1184 | 31 | if (!RD->hasAttr<ConsumableAttr>()) { |
1185 | 3 | S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD; |
1186 | | |
1187 | 3 | return false; |
1188 | 3 | } |
1189 | 28 | } |
1190 | | |
1191 | 28 | return true; |
1192 | 28 | } |
1193 | | |
1194 | 16 | static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1195 | 16 | if (!checkAttributeAtLeastNumArgs(S, AL, 1)) |
1196 | 1 | return; |
1197 | | |
1198 | 15 | if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) |
1199 | 1 | return; |
1200 | | |
1201 | 14 | SmallVector<CallableWhenAttr::ConsumedState, 3> States; |
1202 | 32 | for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex18 ) { |
1203 | 20 | CallableWhenAttr::ConsumedState CallableState; |
1204 | | |
1205 | 20 | StringRef StateString; |
1206 | 20 | SourceLocation Loc; |
1207 | 20 | if (AL.isArgIdent(ArgIndex)) { |
1208 | 1 | IdentifierLoc *Ident = AL.getArgAsIdent(ArgIndex); |
1209 | 1 | StateString = Ident->Ident->getName(); |
1210 | 1 | Loc = Ident->Loc; |
1211 | 19 | } else { |
1212 | 19 | if (!S.checkStringLiteralArgumentAttr(AL, ArgIndex, StateString, &Loc)) |
1213 | 1 | return; |
1214 | 19 | } |
1215 | | |
1216 | 19 | if (!CallableWhenAttr::ConvertStrToConsumedState(StateString, |
1217 | 1 | CallableState)) { |
1218 | 1 | S.Diag(Loc, diag::warn_attribute_type_not_supported) << AL << StateString; |
1219 | 1 | return; |
1220 | 1 | } |
1221 | | |
1222 | 18 | States.push_back(CallableState); |
1223 | 18 | } |
1224 | | |
1225 | 12 | D->addAttr(::new (S.Context) |
1226 | 12 | CallableWhenAttr(S.Context, AL, States.data(), States.size())); |
1227 | 12 | } |
1228 | | |
1229 | 7 | static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1230 | 7 | ParamTypestateAttr::ConsumedState ParamState; |
1231 | | |
1232 | 7 | if (AL.isArgIdent(0)) { |
1233 | 7 | IdentifierLoc *Ident = AL.getArgAsIdent(0); |
1234 | 7 | StringRef StateString = Ident->Ident->getName(); |
1235 | | |
1236 | 7 | if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString, |
1237 | 0 | ParamState)) { |
1238 | 0 | S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) |
1239 | 0 | << AL << StateString; |
1240 | 0 | return; |
1241 | 0 | } |
1242 | 0 | } else { |
1243 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_type) |
1244 | 0 | << AL << AANT_ArgumentIdentifier; |
1245 | 0 | return; |
1246 | 0 | } |
1247 | | |
1248 | | // FIXME: This check is currently being done in the analysis. It can be |
1249 | | // enabled here only after the parser propagates attributes at |
1250 | | // template specialization definition, not declaration. |
1251 | | //QualType ReturnType = cast<ParmVarDecl>(D)->getType(); |
1252 | | //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); |
1253 | | // |
1254 | | //if (!RD || !RD->hasAttr<ConsumableAttr>()) { |
1255 | | // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) << |
1256 | | // ReturnType.getAsString(); |
1257 | | // return; |
1258 | | //} |
1259 | | |
1260 | 7 | D->addAttr(::new (S.Context) ParamTypestateAttr(S.Context, AL, ParamState)); |
1261 | 7 | } |
1262 | | |
1263 | 15 | static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1264 | 15 | ReturnTypestateAttr::ConsumedState ReturnState; |
1265 | | |
1266 | 15 | if (AL.isArgIdent(0)) { |
1267 | 14 | IdentifierLoc *IL = AL.getArgAsIdent(0); |
1268 | 14 | if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), |
1269 | 1 | ReturnState)) { |
1270 | 1 | S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL |
1271 | 1 | << IL->Ident; |
1272 | 1 | return; |
1273 | 1 | } |
1274 | 1 | } else { |
1275 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_argument_type) |
1276 | 1 | << AL << AANT_ArgumentIdentifier; |
1277 | 1 | return; |
1278 | 1 | } |
1279 | | |
1280 | | // FIXME: This check is currently being done in the analysis. It can be |
1281 | | // enabled here only after the parser propagates attributes at |
1282 | | // template specialization definition, not declaration. |
1283 | | //QualType ReturnType; |
1284 | | // |
1285 | | //if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) { |
1286 | | // ReturnType = Param->getType(); |
1287 | | // |
1288 | | //} else if (const CXXConstructorDecl *Constructor = |
1289 | | // dyn_cast<CXXConstructorDecl>(D)) { |
1290 | | // ReturnType = Constructor->getThisType()->getPointeeType(); |
1291 | | // |
1292 | | //} else { |
1293 | | // |
1294 | | // ReturnType = cast<FunctionDecl>(D)->getCallResultType(); |
1295 | | //} |
1296 | | // |
1297 | | //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); |
1298 | | // |
1299 | | //if (!RD || !RD->hasAttr<ConsumableAttr>()) { |
1300 | | // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) << |
1301 | | // ReturnType.getAsString(); |
1302 | | // return; |
1303 | | //} |
1304 | | |
1305 | 13 | D->addAttr(::new (S.Context) ReturnTypestateAttr(S.Context, AL, ReturnState)); |
1306 | 13 | } |
1307 | | |
1308 | 10 | static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1309 | 10 | if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) |
1310 | 1 | return; |
1311 | | |
1312 | 9 | SetTypestateAttr::ConsumedState NewState; |
1313 | 9 | if (AL.isArgIdent(0)) { |
1314 | 9 | IdentifierLoc *Ident = AL.getArgAsIdent(0); |
1315 | 9 | StringRef Param = Ident->Ident->getName(); |
1316 | 9 | if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) { |
1317 | 0 | S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL |
1318 | 0 | << Param; |
1319 | 0 | return; |
1320 | 0 | } |
1321 | 0 | } else { |
1322 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_type) |
1323 | 0 | << AL << AANT_ArgumentIdentifier; |
1324 | 0 | return; |
1325 | 0 | } |
1326 | | |
1327 | 9 | D->addAttr(::new (S.Context) SetTypestateAttr(S.Context, AL, NewState)); |
1328 | 9 | } |
1329 | | |
1330 | 6 | static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1331 | 6 | if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) |
1332 | 1 | return; |
1333 | | |
1334 | 5 | TestTypestateAttr::ConsumedState TestState; |
1335 | 5 | if (AL.isArgIdent(0)) { |
1336 | 5 | IdentifierLoc *Ident = AL.getArgAsIdent(0); |
1337 | 5 | StringRef Param = Ident->Ident->getName(); |
1338 | 5 | if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) { |
1339 | 0 | S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL |
1340 | 0 | << Param; |
1341 | 0 | return; |
1342 | 0 | } |
1343 | 0 | } else { |
1344 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_type) |
1345 | 0 | << AL << AANT_ArgumentIdentifier; |
1346 | 0 | return; |
1347 | 0 | } |
1348 | | |
1349 | 5 | D->addAttr(::new (S.Context) TestTypestateAttr(S.Context, AL, TestState)); |
1350 | 5 | } |
1351 | | |
1352 | 2.62k | static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1353 | | // Remember this typedef decl, we will need it later for diagnostics. |
1354 | 2.62k | S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D)); |
1355 | 2.62k | } |
1356 | | |
1357 | 39.1k | static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1358 | 39.1k | if (auto *TD = dyn_cast<TagDecl>(D)) |
1359 | 37.5k | TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); |
1360 | 1.57k | else if (auto *FD = dyn_cast<FieldDecl>(D)) { |
1361 | 1.56k | bool BitfieldByteAligned = (!FD->getType()->isDependentType() && |
1362 | 1.56k | !FD->getType()->isIncompleteType() && |
1363 | 1.30k | FD->isBitField() && |
1364 | 30 | S.Context.getTypeAlign(FD->getType()) <= 8); |
1365 | | |
1366 | 1.56k | if (S.getASTContext().getTargetInfo().getTriple().isPS4()) { |
1367 | 6 | if (BitfieldByteAligned) |
1368 | | // The PS4 target needs to maintain ABI backwards compatibility. |
1369 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type) |
1370 | 1 | << AL << FD->getType(); |
1371 | 5 | else |
1372 | 5 | FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); |
1373 | 1.56k | } else { |
1374 | | // Report warning about changed offset in the newer compiler versions. |
1375 | 1.56k | if (BitfieldByteAligned) |
1376 | 2 | S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield); |
1377 | | |
1378 | 1.56k | FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); |
1379 | 1.56k | } |
1380 | | |
1381 | 1.56k | } else |
1382 | 10 | S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; |
1383 | 39.1k | } |
1384 | | |
1385 | 14.1k | static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) { |
1386 | 14.1k | auto *RD = cast<CXXRecordDecl>(D); |
1387 | 14.1k | ClassTemplateDecl *CTD = RD->getDescribedClassTemplate(); |
1388 | 14.1k | assert(CTD && "attribute does not appertain to this declaration"); |
1389 | | |
1390 | 14.1k | ParsedType PT = AL.getTypeArg(); |
1391 | 14.1k | TypeSourceInfo *TSI = nullptr; |
1392 | 14.1k | QualType T = S.GetTypeFromParser(PT, &TSI); |
1393 | 14.1k | if (!TSI) |
1394 | 0 | TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc()); |
1395 | | |
1396 | 14.1k | if (!T.hasQualifiers() && T->isTypedefNameType()14.1k ) { |
1397 | | // Find the template name, if this type names a template specialization. |
1398 | 14.1k | const TemplateDecl *Template = nullptr; |
1399 | 14.1k | if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>( |
1400 | 14.1k | T->getAsCXXRecordDecl())) { |
1401 | 14.1k | Template = CTSD->getSpecializedTemplate(); |
1402 | 6 | } else if (const auto *TST = T->getAs<TemplateSpecializationType>()) { |
1403 | 8 | while (TST && TST->isTypeAlias()) |
1404 | 2 | TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); |
1405 | 6 | if (TST) |
1406 | 6 | Template = TST->getTemplateName().getAsTemplateDecl(); |
1407 | 6 | } |
1408 | | |
1409 | 14.1k | if (Template && declaresSameEntity(Template, CTD)) { |
1410 | 14.1k | D->addAttr(::new (S.Context) PreferredNameAttr(S.Context, AL, TSI)); |
1411 | 14.1k | return; |
1412 | 14.1k | } |
1413 | 8 | } |
1414 | | |
1415 | 8 | S.Diag(AL.getLoc(), diag::err_attribute_preferred_name_arg_invalid) |
1416 | 8 | << T << CTD; |
1417 | 8 | if (const auto *TT = T->getAs<TypedefType>()) |
1418 | 4 | S.Diag(TT->getDecl()->getLocation(), diag::note_entity_declared_at) |
1419 | 4 | << TT->getDecl(); |
1420 | 8 | } |
1421 | | |
1422 | 134 | static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { |
1423 | | // The IBOutlet/IBOutletCollection attributes only apply to instance |
1424 | | // variables or properties of Objective-C classes. The outlet must also |
1425 | | // have an object reference type. |
1426 | 134 | if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) { |
1427 | 39 | if (!VD->getType()->getAs<ObjCObjectPointerType>()) { |
1428 | 10 | S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) |
1429 | 10 | << AL << VD->getType() << 0; |
1430 | 10 | return false; |
1431 | 10 | } |
1432 | 95 | } |
1433 | 95 | else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { |
1434 | 95 | if (!PD->getType()->getAs<ObjCObjectPointerType>()) { |
1435 | 8 | S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) |
1436 | 8 | << AL << PD->getType() << 1; |
1437 | 8 | return false; |
1438 | 8 | } |
1439 | 0 | } |
1440 | 0 | else { |
1441 | 0 | S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL; |
1442 | 0 | return false; |
1443 | 0 | } |
1444 | | |
1445 | 116 | return true; |
1446 | 116 | } |
1447 | | |
1448 | 99 | static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) { |
1449 | 99 | if (!checkIBOutletCommon(S, D, AL)) |
1450 | 14 | return; |
1451 | | |
1452 | 85 | D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL)); |
1453 | 85 | } |
1454 | | |
1455 | 35 | static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { |
1456 | | |
1457 | | // The iboutletcollection attribute can have zero or one arguments. |
1458 | 35 | if (AL.getNumArgs() > 1) { |
1459 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; |
1460 | 0 | return; |
1461 | 0 | } |
1462 | | |
1463 | 35 | if (!checkIBOutletCommon(S, D, AL)) |
1464 | 4 | return; |
1465 | | |
1466 | 31 | ParsedType PT; |
1467 | | |
1468 | 31 | if (AL.hasParsedType()) |
1469 | 23 | PT = AL.getTypeArg(); |
1470 | 8 | else { |
1471 | 8 | PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(), |
1472 | 8 | S.getScopeForContext(D->getDeclContext()->getParent())); |
1473 | 8 | if (!PT) { |
1474 | 0 | S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; |
1475 | 0 | return; |
1476 | 0 | } |
1477 | 31 | } |
1478 | | |
1479 | 31 | TypeSourceInfo *QTLoc = nullptr; |
1480 | 31 | QualType QT = S.GetTypeFromParser(PT, &QTLoc); |
1481 | 31 | if (!QTLoc) |
1482 | 8 | QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc()); |
1483 | | |
1484 | | // Diagnose use of non-object type in iboutletcollection attribute. |
1485 | | // FIXME. Gnu attribute extension ignores use of builtin types in |
1486 | | // attributes. So, __attribute__((iboutletcollection(char))) will be |
1487 | | // treated as __attribute__((iboutletcollection())). |
1488 | 31 | if (!QT->isObjCIdType() && !QT->isObjCObjectType()26 ) { |
1489 | 4 | S.Diag(AL.getLoc(), |
1490 | 2 | QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype |
1491 | 2 | : diag::err_iboutletcollection_type) << QT; |
1492 | 4 | return; |
1493 | 4 | } |
1494 | | |
1495 | 27 | D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc)); |
1496 | 27 | } |
1497 | | |
1498 | 102k | bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { |
1499 | 102k | if (RefOkay) { |
1500 | 31.2k | if (T->isReferenceType()) |
1501 | 2 | return true; |
1502 | 71.5k | } else { |
1503 | 71.5k | T = T.getNonReferenceType(); |
1504 | 71.5k | } |
1505 | | |
1506 | | // The nonnull attribute, and other similar attributes, can be applied to a |
1507 | | // transparent union that contains a pointer type. |
1508 | 102k | if (const RecordType *UT = T->getAsUnionType()) { |
1509 | 18 | if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { |
1510 | 18 | RecordDecl *UD = UT->getDecl(); |
1511 | 23 | for (const auto *I : UD->fields()) { |
1512 | 23 | QualType QT = I->getType(); |
1513 | 23 | if (QT->isAnyPointerType() || QT->isBlockPointerType()5 ) |
1514 | 18 | return true; |
1515 | 23 | } |
1516 | 18 | } |
1517 | 18 | } |
1518 | | |
1519 | 102k | return T->isAnyPointerType() || T->isBlockPointerType()33.3k ; |
1520 | 102k | } |
1521 | | |
1522 | | static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL, |
1523 | | SourceRange AttrParmRange, |
1524 | | SourceRange TypeRange, |
1525 | 70.5k | bool isReturnValue = false) { |
1526 | 70.5k | if (!S.isValidPointerAttrType(T)) { |
1527 | 17 | if (isReturnValue) |
1528 | 6 | S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) |
1529 | 6 | << AL << AttrParmRange << TypeRange; |
1530 | 11 | else |
1531 | 11 | S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) |
1532 | 11 | << AL << AttrParmRange << TypeRange << 0; |
1533 | 17 | return false; |
1534 | 17 | } |
1535 | 70.5k | return true; |
1536 | 70.5k | } |
1537 | | |
1538 | 92.9k | static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1539 | 92.9k | SmallVector<ParamIdx, 8> NonNullArgs; |
1540 | 163k | for (unsigned I = 0; I < AL.getNumArgs(); ++I70.4k ) { |
1541 | 70.4k | Expr *Ex = AL.getArgAsExpr(I); |
1542 | 70.4k | ParamIdx Idx; |
1543 | 70.4k | if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx)) |
1544 | 5 | return; |
1545 | | |
1546 | | // Is the function argument a pointer type? |
1547 | 70.4k | if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) && |
1548 | 70.4k | !attrNonNullArgCheck( |
1549 | 70.4k | S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL, |
1550 | 70.4k | Ex->getSourceRange(), |
1551 | 70.4k | getFunctionOrMethodParamRange(D, Idx.getASTIndex()))) |
1552 | 7 | continue; |
1553 | | |
1554 | 70.4k | NonNullArgs.push_back(Idx); |
1555 | 70.4k | } |
1556 | | |
1557 | | // If no arguments were specified to __attribute__((nonnull)) then all pointer |
1558 | | // arguments have a nonnull attribute; warn if there aren't any. Skip this |
1559 | | // check if the attribute came from a macro expansion or a template |
1560 | | // instantiation. |
1561 | 92.9k | if (NonNullArgs.empty() && AL.getLoc().isFileID()24.8k && |
1562 | 65 | !S.inTemplateInstantiation()) { |
1563 | 65 | bool AnyPointers = isFunctionOrMethodVariadic(D); |
1564 | 65 | for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); |
1565 | 120 | I != E && !AnyPointers82 ; ++I55 ) { |
1566 | 55 | QualType T = getFunctionOrMethodParamType(D, I); |
1567 | 55 | if (T->isDependentType() || S.isValidPointerAttrType(T)53 ) |
1568 | 47 | AnyPointers = true; |
1569 | 55 | } |
1570 | | |
1571 | 65 | if (!AnyPointers) |
1572 | 6 | S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers); |
1573 | 65 | } |
1574 | | |
1575 | 92.9k | ParamIdx *Start = NonNullArgs.data(); |
1576 | 92.9k | unsigned Size = NonNullArgs.size(); |
1577 | 92.9k | llvm::array_pod_sort(Start, Start + Size); |
1578 | 92.9k | D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, Start, Size)); |
1579 | 92.9k | } |
1580 | | |
1581 | | static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, |
1582 | 32 | const ParsedAttr &AL) { |
1583 | 32 | if (AL.getNumArgs() > 0) { |
1584 | 6 | if (D->getFunctionType()) { |
1585 | 3 | handleNonNullAttr(S, D, AL); |
1586 | 3 | } else { |
1587 | 3 | S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args) |
1588 | 3 | << D->getSourceRange(); |
1589 | 3 | } |
1590 | 6 | return; |
1591 | 6 | } |
1592 | | |
1593 | | // Is the argument a pointer type? |
1594 | 26 | if (!attrNonNullArgCheck(S, D->getType(), AL, SourceRange(), |
1595 | 26 | D->getSourceRange())) |
1596 | 4 | return; |
1597 | | |
1598 | 22 | D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, nullptr, 0)); |
1599 | 22 | } |
1600 | | |
1601 | 29 | static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1602 | 29 | QualType ResultType = getFunctionOrMethodResultType(D); |
1603 | 29 | SourceRange SR = getFunctionOrMethodResultSourceRange(D); |
1604 | 29 | if (!attrNonNullArgCheck(S, ResultType, AL, SourceRange(), SR, |
1605 | 29 | /* isReturnValue */ true)) |
1606 | 6 | return; |
1607 | | |
1608 | 23 | D->addAttr(::new (S.Context) ReturnsNonNullAttr(S.Context, AL)); |
1609 | 23 | } |
1610 | | |
1611 | 31.2k | static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1612 | 31.2k | if (D->isInvalidDecl()) |
1613 | 0 | return; |
1614 | | |
1615 | | // noescape only applies to pointer types. |
1616 | 31.2k | QualType T = cast<ParmVarDecl>(D)->getType(); |
1617 | 31.2k | if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { |
1618 | 6 | S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) |
1619 | 6 | << AL << AL.getRange() << 0; |
1620 | 6 | return; |
1621 | 6 | } |
1622 | | |
1623 | 31.2k | D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL)); |
1624 | 31.2k | } |
1625 | | |
1626 | 27 | static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1627 | 27 | Expr *E = AL.getArgAsExpr(0), |
1628 | 18 | *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1)9 : nullptr; |
1629 | 27 | S.AddAssumeAlignedAttr(D, AL, E, OE); |
1630 | 27 | } |
1631 | | |
1632 | 36 | static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1633 | 36 | S.AddAllocAlignAttr(D, AL, AL.getArgAsExpr(0)); |
1634 | 36 | } |
1635 | | |
1636 | | void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, |
1637 | 35 | Expr *OE) { |
1638 | 35 | QualType ResultType = getFunctionOrMethodResultType(D); |
1639 | 35 | SourceRange SR = getFunctionOrMethodResultSourceRange(D); |
1640 | | |
1641 | 35 | AssumeAlignedAttr TmpAttr(Context, CI, E, OE); |
1642 | 35 | SourceLocation AttrLoc = TmpAttr.getLocation(); |
1643 | | |
1644 | 35 | if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) { |
1645 | 3 | Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only) |
1646 | 3 | << &TmpAttr << TmpAttr.getRange() << SR; |
1647 | 3 | return; |
1648 | 3 | } |
1649 | | |
1650 | 32 | if (!E->isValueDependent()) { |
1651 | 28 | Optional<llvm::APSInt> I = llvm::APSInt(64); |
1652 | 28 | if (!(I = E->getIntegerConstantExpr(Context))) { |
1653 | 0 | if (OE) |
1654 | 0 | Diag(AttrLoc, diag::err_attribute_argument_n_type) |
1655 | 0 | << &TmpAttr << 1 << AANT_ArgumentIntegerConstant |
1656 | 0 | << E->getSourceRange(); |
1657 | 0 | else |
1658 | 0 | Diag(AttrLoc, diag::err_attribute_argument_type) |
1659 | 0 | << &TmpAttr << AANT_ArgumentIntegerConstant |
1660 | 0 | << E->getSourceRange(); |
1661 | 0 | return; |
1662 | 0 | } |
1663 | | |
1664 | 28 | if (!I->isPowerOf2()) { |
1665 | 5 | Diag(AttrLoc, diag::err_alignment_not_power_of_two) |
1666 | 5 | << E->getSourceRange(); |
1667 | 5 | return; |
1668 | 5 | } |
1669 | | |
1670 | 23 | if (*I > Sema::MaximumAlignment) |
1671 | 5 | Diag(CI.getLoc(), diag::warn_assume_aligned_too_great) |
1672 | 5 | << CI.getRange() << Sema::MaximumAlignment; |
1673 | 23 | } |
1674 | | |
1675 | 27 | if (OE && !OE->isValueDependent()10 && !OE->isIntegerConstantExpr(Context)8 ) { |
1676 | 0 | Diag(AttrLoc, diag::err_attribute_argument_n_type) |
1677 | 0 | << &TmpAttr << 2 << AANT_ArgumentIntegerConstant |
1678 | 0 | << OE->getSourceRange(); |
1679 | 0 | return; |
1680 | 0 | } |
1681 | | |
1682 | 27 | D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE)); |
1683 | 27 | } |
1684 | | |
1685 | | void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, |
1686 | 44 | Expr *ParamExpr) { |
1687 | 44 | QualType ResultType = getFunctionOrMethodResultType(D); |
1688 | | |
1689 | 44 | AllocAlignAttr TmpAttr(Context, CI, ParamIdx()); |
1690 | 44 | SourceLocation AttrLoc = CI.getLoc(); |
1691 | | |
1692 | 44 | if (!ResultType->isDependentType() && |
1693 | 42 | !isValidPointerAttrType(ResultType, /* RefOkay */ true)) { |
1694 | 2 | Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only) |
1695 | 2 | << &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D); |
1696 | 2 | return; |
1697 | 2 | } |
1698 | | |
1699 | 42 | ParamIdx Idx; |
1700 | 42 | const auto *FuncDecl = cast<FunctionDecl>(D); |
1701 | 42 | if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, |
1702 | 42 | /*AttrArgNum=*/1, ParamExpr, Idx)) |
1703 | 5 | return; |
1704 | | |
1705 | 37 | QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); |
1706 | 37 | if (!Ty->isDependentType() && !Ty->isIntegralType(Context)35 && |
1707 | 9 | !Ty->isAlignValT()) { |
1708 | 3 | Diag(ParamExpr->getBeginLoc(), diag::err_attribute_integers_only) |
1709 | 3 | << &TmpAttr |
1710 | 3 | << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); |
1711 | 3 | return; |
1712 | 3 | } |
1713 | | |
1714 | 34 | D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx)); |
1715 | 34 | } |
1716 | | |
1717 | | /// Check if \p AssumptionStr is a known assumption and warn if not. |
1718 | | static void checkAssumptionAttr(Sema &S, SourceLocation Loc, |
1719 | 81 | StringRef AssumptionStr) { |
1720 | 81 | if (llvm::KnownAssumptionStrings.count(AssumptionStr)) |
1721 | 1 | return; |
1722 | | |
1723 | 80 | unsigned BestEditDistance = 3; |
1724 | 80 | StringRef Suggestion; |
1725 | 240 | for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) { |
1726 | 240 | unsigned EditDistance = |
1727 | 240 | AssumptionStr.edit_distance(KnownAssumptionIt.getKey()); |
1728 | 240 | if (EditDistance < BestEditDistance) { |
1729 | 3 | Suggestion = KnownAssumptionIt.getKey(); |
1730 | 3 | BestEditDistance = EditDistance; |
1731 | 3 | } |
1732 | 240 | } |
1733 | | |
1734 | 80 | if (!Suggestion.empty()) |
1735 | 3 | S.Diag(Loc, diag::warn_assume_attribute_string_unknown_suggested) |
1736 | 3 | << AssumptionStr << Suggestion; |
1737 | 77 | else |
1738 | 77 | S.Diag(Loc, diag::warn_assume_attribute_string_unknown) << AssumptionStr; |
1739 | 80 | } |
1740 | | |
1741 | 82 | static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1742 | | // Handle the case where the attribute has a text message. |
1743 | 82 | StringRef Str; |
1744 | 82 | SourceLocation AttrStrLoc; |
1745 | 82 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc)) |
1746 | 1 | return; |
1747 | | |
1748 | 81 | checkAssumptionAttr(S, AttrStrLoc, Str); |
1749 | | |
1750 | 81 | D->addAttr(::new (S.Context) AssumptionAttr(S.Context, AL, Str)); |
1751 | 81 | } |
1752 | | |
1753 | | /// Normalize the attribute, __foo__ becomes foo. |
1754 | | /// Returns true if normalization was applied. |
1755 | 37.9k | static bool normalizeName(StringRef &AttrName) { |
1756 | 37.9k | if (AttrName.size() > 4 && AttrName.startswith("__")37.6k && |
1757 | 34.9k | AttrName.endswith("__")) { |
1758 | 34.9k | AttrName = AttrName.drop_front(2).drop_back(2); |
1759 | 34.9k | return true; |
1760 | 34.9k | } |
1761 | 3.01k | return false; |
1762 | 3.01k | } |
1763 | | |
1764 | 50 | static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1765 | | // This attribute must be applied to a function declaration. The first |
1766 | | // argument to the attribute must be an identifier, the name of the resource, |
1767 | | // for example: malloc. The following arguments must be argument indexes, the |
1768 | | // arguments must be of integer type for Returns, otherwise of pointer type. |
1769 | | // The difference between Holds and Takes is that a pointer may still be used |
1770 | | // after being held. free() should be __attribute((ownership_takes)), whereas |
1771 | | // a list append function may well be __attribute((ownership_holds)). |
1772 | | |
1773 | 50 | if (!AL.isArgIdent(0)) { |
1774 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
1775 | 1 | << AL << 1 << AANT_ArgumentIdentifier; |
1776 | 1 | return; |
1777 | 1 | } |
1778 | | |
1779 | | // Figure out our Kind. |
1780 | 49 | OwnershipAttr::OwnershipKind K = |
1781 | 49 | OwnershipAttr(S.Context, AL, nullptr, nullptr, 0).getOwnKind(); |
1782 | | |
1783 | | // Check arguments. |
1784 | 49 | switch (K) { |
1785 | 12 | case OwnershipAttr::Takes: |
1786 | 31 | case OwnershipAttr::Holds: |
1787 | 31 | if (AL.getNumArgs() < 2) { |
1788 | 2 | S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << AL << 2; |
1789 | 2 | return; |
1790 | 2 | } |
1791 | 29 | break; |
1792 | 18 | case OwnershipAttr::Returns: |
1793 | 18 | if (AL.getNumArgs() > 2) { |
1794 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; |
1795 | 1 | return; |
1796 | 1 | } |
1797 | 17 | break; |
1798 | 46 | } |
1799 | | |
1800 | 46 | IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident; |
1801 | | |
1802 | 46 | StringRef ModuleName = Module->getName(); |
1803 | 46 | if (normalizeName(ModuleName)) { |
1804 | 0 | Module = &S.PP.getIdentifierTable().get(ModuleName); |
1805 | 0 | } |
1806 | | |
1807 | 46 | SmallVector<ParamIdx, 8> OwnershipArgs; |
1808 | 88 | for (unsigned i = 1; i < AL.getNumArgs(); ++i42 ) { |
1809 | 51 | Expr *Ex = AL.getArgAsExpr(i); |
1810 | 51 | ParamIdx Idx; |
1811 | 51 | if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) |
1812 | 3 | return; |
1813 | | |
1814 | | // Is the function argument a pointer type? |
1815 | 48 | QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex()); |
1816 | 48 | int Err = -1; // No error |
1817 | 48 | switch (K) { |
1818 | 15 | case OwnershipAttr::Takes: |
1819 | 37 | case OwnershipAttr::Holds: |
1820 | 37 | if (!T->isAnyPointerType() && !T->isBlockPointerType()1 ) |
1821 | 1 | Err = 0; |
1822 | 37 | break; |
1823 | 11 | case OwnershipAttr::Returns: |
1824 | 11 | if (!T->isIntegerType()) |
1825 | 2 | Err = 1; |
1826 | 11 | break; |
1827 | 48 | } |
1828 | 48 | if (-1 != Err) { |
1829 | 3 | S.Diag(AL.getLoc(), diag::err_ownership_type) << AL << Err |
1830 | 3 | << Ex->getSourceRange(); |
1831 | 3 | return; |
1832 | 3 | } |
1833 | | |
1834 | | // Check we don't have a conflict with another ownership attribute. |
1835 | 45 | for (const auto *I : D->specific_attrs<OwnershipAttr>()) { |
1836 | | // Cannot have two ownership attributes of different kinds for the same |
1837 | | // index. |
1838 | 8 | if (I->getOwnKind() != K && I->args_end() != |
1839 | 1 | std::find(I->args_begin(), I->args_end(), Idx)) { |
1840 | 1 | S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; |
1841 | 1 | return; |
1842 | 7 | } else if (K == OwnershipAttr::Returns && |
1843 | 2 | I->getOwnKind() == OwnershipAttr::Returns) { |
1844 | | // A returns attribute conflicts with any other returns attribute using |
1845 | | // a different index. |
1846 | 2 | if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) { |
1847 | 2 | S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch) |
1848 | 2 | << I->args_begin()->getSourceIndex(); |
1849 | 2 | if (I->args_size()) |
1850 | 2 | S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch) |
1851 | 2 | << Idx.getSourceIndex() << Ex->getSourceRange(); |
1852 | 2 | return; |
1853 | 2 | } |
1854 | 2 | } |
1855 | 8 | } |
1856 | 42 | OwnershipArgs.push_back(Idx); |
1857 | 42 | } |
1858 | | |
1859 | 37 | ParamIdx *Start = OwnershipArgs.data(); |
1860 | 37 | unsigned Size = OwnershipArgs.size(); |
1861 | 37 | llvm::array_pod_sort(Start, Start + Size); |
1862 | 37 | D->addAttr(::new (S.Context) |
1863 | 37 | OwnershipAttr(S.Context, AL, Module, Start, Size)); |
1864 | 37 | } |
1865 | | |
1866 | 48 | static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1867 | | // Check the attribute arguments. |
1868 | 48 | if (AL.getNumArgs() > 1) { |
1869 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; |
1870 | 0 | return; |
1871 | 0 | } |
1872 | | |
1873 | | // gcc rejects |
1874 | | // class c { |
1875 | | // static int a __attribute__((weakref ("v2"))); |
1876 | | // static int b() __attribute__((weakref ("f3"))); |
1877 | | // }; |
1878 | | // and ignores the attributes of |
1879 | | // void f(void) { |
1880 | | // static int a __attribute__((weakref ("v2"))); |
1881 | | // } |
1882 | | // we reject them |
1883 | 48 | const DeclContext *Ctx = D->getDeclContext()->getRedeclContext(); |
1884 | 48 | if (!Ctx->isFileContext()) { |
1885 | 3 | S.Diag(AL.getLoc(), diag::err_attribute_weakref_not_global_context) |
1886 | 3 | << cast<NamedDecl>(D); |
1887 | 3 | return; |
1888 | 3 | } |
1889 | | |
1890 | | // The GCC manual says |
1891 | | // |
1892 | | // At present, a declaration to which `weakref' is attached can only |
1893 | | // be `static'. |
1894 | | // |
1895 | | // It also says |
1896 | | // |
1897 | | // Without a TARGET, |
1898 | | // given as an argument to `weakref' or to `alias', `weakref' is |
1899 | | // equivalent to `weak'. |
1900 | | // |
1901 | | // gcc 4.4.1 will accept |
1902 | | // int a7 __attribute__((weakref)); |
1903 | | // as |
1904 | | // int a7 __attribute__((weak)); |
1905 | | // This looks like a bug in gcc. We reject that for now. We should revisit |
1906 | | // it if this behaviour is actually used. |
1907 | | |
1908 | | // GCC rejects |
1909 | | // static ((alias ("y"), weakref)). |
1910 | | // Should we? How to check that weakref is before or after alias? |
1911 | | |
1912 | | // FIXME: it would be good for us to keep the WeakRefAttr as-written instead |
1913 | | // of transforming it into an AliasAttr. The WeakRefAttr never uses the |
1914 | | // StringRef parameter it was given anyway. |
1915 | 45 | StringRef Str; |
1916 | 45 | if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str)36 ) |
1917 | | // GCC will accept anything as the argument of weakref. Should we |
1918 | | // check for an existing decl? |
1919 | 35 | D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str)); |
1920 | | |
1921 | 45 | D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL)); |
1922 | 45 | } |
1923 | | |
1924 | 15 | static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1925 | 15 | StringRef Str; |
1926 | 15 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) |
1927 | 0 | return; |
1928 | | |
1929 | | // Aliases should be on declarations, not definitions. |
1930 | 15 | const auto *FD = cast<FunctionDecl>(D); |
1931 | 15 | if (FD->isThisDeclarationADefinition()) { |
1932 | 0 | S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 1; |
1933 | 0 | return; |
1934 | 0 | } |
1935 | | |
1936 | 15 | D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str)); |
1937 | 15 | } |
1938 | | |
1939 | 155 | static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1940 | 155 | StringRef Str; |
1941 | 155 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) |
1942 | 0 | return; |
1943 | | |
1944 | 155 | if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { |
1945 | 1 | S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_darwin); |
1946 | 1 | return; |
1947 | 1 | } |
1948 | 154 | if (S.Context.getTargetInfo().getTriple().isNVPTX()) { |
1949 | 1 | S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_nvptx); |
1950 | 1 | } |
1951 | | |
1952 | | // Aliases should be on declarations, not definitions. |
1953 | 154 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
1954 | 106 | if (FD->isThisDeclarationADefinition()) { |
1955 | 0 | S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 0; |
1956 | 0 | return; |
1957 | 0 | } |
1958 | 48 | } else { |
1959 | 48 | const auto *VD = cast<VarDecl>(D); |
1960 | 48 | if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()11 ) { |
1961 | 1 | S.Diag(AL.getLoc(), diag::err_alias_is_definition) << VD << 0; |
1962 | 1 | return; |
1963 | 1 | } |
1964 | 153 | } |
1965 | | |
1966 | | // Mark target used to prevent unneeded-internal-declaration warnings. |
1967 | 153 | if (!S.LangOpts.CPlusPlus) { |
1968 | | // FIXME: demangle Str for C++, as the attribute refers to the mangled |
1969 | | // linkage name, not the pre-mangled identifier. |
1970 | 117 | const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc()); |
1971 | 117 | LookupResult LR(S, target, Sema::LookupOrdinaryName); |
1972 | 117 | if (S.LookupQualifiedName(LR, S.getCurLexicalContext())) |
1973 | 96 | for (NamedDecl *ND : LR) |
1974 | 96 | ND->markUsed(S.Context); |
1975 | 117 | } |
1976 | | |
1977 | 153 | D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str)); |
1978 | 153 | } |
1979 | | |
1980 | 25 | static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1981 | 25 | StringRef Model; |
1982 | 25 | SourceLocation LiteralLoc; |
1983 | | // Check that it is a string. |
1984 | 25 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Model, &LiteralLoc)) |
1985 | 1 | return; |
1986 | | |
1987 | | // Check that the value. |
1988 | 24 | if (Model != "global-dynamic" && Model != "local-dynamic"20 |
1989 | 17 | && Model != "initial-exec" && Model != "local-exec"5 ) { |
1990 | 1 | S.Diag(LiteralLoc, diag::err_attr_tlsmodel_arg); |
1991 | 1 | return; |
1992 | 1 | } |
1993 | | |
1994 | 23 | D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model)); |
1995 | 23 | } |
1996 | | |
1997 | 15.1k | static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
1998 | 15.1k | QualType ResultType = getFunctionOrMethodResultType(D); |
1999 | 15.1k | if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()5 ) { |
2000 | 15.0k | D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL)); |
2001 | 15.0k | return; |
2002 | 15.0k | } |
2003 | | |
2004 | 4 | S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) |
2005 | 4 | << AL << getFunctionOrMethodResultSourceRange(D); |
2006 | 4 | } |
2007 | | |
2008 | 110 | static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2009 | 110 | FunctionDecl *FD = cast<FunctionDecl>(D); |
2010 | | |
2011 | 110 | if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { |
2012 | 18 | if (MD->getParent()->isLambda()) { |
2013 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_dll_lambda) << AL; |
2014 | 1 | return; |
2015 | 1 | } |
2016 | 109 | } |
2017 | | |
2018 | 109 | if (!checkAttributeAtLeastNumArgs(S, AL, 1)) |
2019 | 2 | return; |
2020 | | |
2021 | 107 | SmallVector<IdentifierInfo *, 8> CPUs; |
2022 | 266 | for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo159 ) { |
2023 | 163 | if (!AL.isArgIdent(ArgNo)) { |
2024 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_type) |
2025 | 0 | << AL << AANT_ArgumentIdentifier; |
2026 | 0 | return; |
2027 | 0 | } |
2028 | | |
2029 | 163 | IdentifierLoc *CPUArg = AL.getArgAsIdent(ArgNo); |
2030 | 163 | StringRef CPUName = CPUArg->Ident->getName().trim(); |
2031 | | |
2032 | 163 | if (!S.Context.getTargetInfo().validateCPUSpecificCPUDispatch(CPUName)) { |
2033 | 2 | S.Diag(CPUArg->Loc, diag::err_invalid_cpu_specific_dispatch_value) |
2034 | 2 | << CPUName << (AL.getKind() == ParsedAttr::AT_CPUDispatch); |
2035 | 2 | return; |
2036 | 2 | } |
2037 | | |
2038 | 161 | const TargetInfo &Target = S.Context.getTargetInfo(); |
2039 | 161 | if (llvm::any_of(CPUs, [CPUName, &Target](const IdentifierInfo *Cur) { |
2040 | 83 | return Target.CPUSpecificManglingCharacter(CPUName) == |
2041 | 83 | Target.CPUSpecificManglingCharacter(Cur->getName()); |
2042 | 2 | })) { |
2043 | 2 | S.Diag(AL.getLoc(), diag::warn_multiversion_duplicate_entries); |
2044 | 2 | return; |
2045 | 2 | } |
2046 | 159 | CPUs.push_back(CPUArg->Ident); |
2047 | 159 | } |
2048 | | |
2049 | 103 | FD->setIsMultiVersion(true); |
2050 | 103 | if (AL.getKind() == ParsedAttr::AT_CPUSpecific) |
2051 | 70 | D->addAttr(::new (S.Context) |
2052 | 70 | CPUSpecificAttr(S.Context, AL, CPUs.data(), CPUs.size())); |
2053 | 33 | else |
2054 | 33 | D->addAttr(::new (S.Context) |
2055 | 33 | CPUDispatchAttr(S.Context, AL, CPUs.data(), CPUs.size())); |
2056 | 103 | } |
2057 | | |
2058 | 10 | static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2059 | 10 | if (S.LangOpts.CPlusPlus) { |
2060 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) |
2061 | 1 | << AL << AttributeLangSupport::Cpp; |
2062 | 1 | return; |
2063 | 1 | } |
2064 | | |
2065 | 9 | if (CommonAttr *CA = S.mergeCommonAttr(D, AL)) |
2066 | 8 | D->addAttr(CA); |
2067 | 9 | } |
2068 | | |
2069 | 100 | static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2070 | 100 | if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()2 ) { |
2071 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL; |
2072 | 1 | return; |
2073 | 1 | } |
2074 | | |
2075 | 99 | const auto *FD = cast<FunctionDecl>(D); |
2076 | 99 | if (!FD->isExternallyVisible()) { |
2077 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static); |
2078 | 1 | return; |
2079 | 1 | } |
2080 | | |
2081 | 98 | D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL)); |
2082 | 98 | } |
2083 | | |
2084 | 31 | static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2085 | 31 | if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL)) |
2086 | 1 | return; |
2087 | | |
2088 | 30 | if (AL.isDeclspecAttribute()) { |
2089 | 9 | const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); |
2090 | 9 | const auto &Arch = Triple.getArch(); |
2091 | 9 | if (Arch != llvm::Triple::x86 && |
2092 | 2 | (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) { |
2093 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch) |
2094 | 1 | << AL << Triple.getArchName(); |
2095 | 1 | return; |
2096 | 1 | } |
2097 | 29 | } |
2098 | | |
2099 | 29 | D->addAttr(::new (S.Context) NakedAttr(S.Context, AL)); |
2100 | 29 | } |
2101 | | |
2102 | 8.18k | static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { |
2103 | 8.18k | if (hasDeclarator(D)) return8.16k ; |
2104 | | |
2105 | 19 | if (!isa<ObjCMethodDecl>(D)) { |
2106 | 4 | S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) |
2107 | 4 | << Attrs << ExpectedFunctionOrMethod; |
2108 | 4 | return; |
2109 | 4 | } |
2110 | | |
2111 | 15 | D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs)); |
2112 | 15 | } |
2113 | | |
2114 | 19 | static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { |
2115 | 19 | if (!S.getLangOpts().CFProtectionBranch) |
2116 | 0 | S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored); |
2117 | 19 | else |
2118 | 19 | handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs); |
2119 | 19 | } |
2120 | | |
2121 | 85.1k | bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { |
2122 | 85.1k | if (!checkAttributeNumArgs(*this, Attrs, 0)) { |
2123 | 7 | Attrs.setInvalid(); |
2124 | 7 | return true; |
2125 | 7 | } |
2126 | | |
2127 | 85.1k | return false; |
2128 | 85.1k | } |
2129 | | |
2130 | 40.6M | bool Sema::CheckAttrTarget(const ParsedAttr &AL) { |
2131 | | // Check whether the attribute is valid on the current target. |
2132 | 40.6M | if (!AL.existsInTarget(Context.getTargetInfo())) { |
2133 | 11 | Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) |
2134 | 11 | << AL << AL.getRange(); |
2135 | 11 | AL.setInvalid(); |
2136 | 11 | return true; |
2137 | 11 | } |
2138 | | |
2139 | 40.6M | return false; |
2140 | 40.6M | } |
2141 | | |
2142 | 7 | static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2143 | | |
2144 | | // The checking path for 'noreturn' and 'analyzer_noreturn' are different |
2145 | | // because 'analyzer_noreturn' does not impact the type. |
2146 | 7 | if (!isFunctionOrMethodOrBlock(D)) { |
2147 | 0 | ValueDecl *VD = dyn_cast<ValueDecl>(D); |
2148 | 0 | if (!VD || (!VD->getType()->isBlockPointerType() && |
2149 | 0 | !VD->getType()->isFunctionPointerType())) { |
2150 | 0 | S.Diag(AL.getLoc(), AL.isCXX11Attribute() |
2151 | 0 | ? diag::err_attribute_wrong_decl_type |
2152 | 0 | : diag::warn_attribute_wrong_decl_type) |
2153 | 0 | << AL << ExpectedFunctionMethodOrBlock; |
2154 | 0 | return; |
2155 | 0 | } |
2156 | 7 | } |
2157 | | |
2158 | 7 | D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(S.Context, AL)); |
2159 | 7 | } |
2160 | | |
2161 | | // PS3 PPU-specific. |
2162 | 17 | static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2163 | | /* |
2164 | | Returning a Vector Class in Registers |
2165 | | |
2166 | | According to the PPU ABI specifications, a class with a single member of |
2167 | | vector type is returned in memory when used as the return value of a |
2168 | | function. |
2169 | | This results in inefficient code when implementing vector classes. To return |
2170 | | the value in a single vector register, add the vecreturn attribute to the |
2171 | | class definition. This attribute is also applicable to struct types. |
2172 | | |
2173 | | Example: |
2174 | | |
2175 | | struct Vector |
2176 | | { |
2177 | | __vector float xyzw; |
2178 | | } __attribute__((vecreturn)); |
2179 | | |
2180 | | Vector Add(Vector lhs, Vector rhs) |
2181 | | { |
2182 | | Vector result; |
2183 | | result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); |
2184 | | return result; // This will be returned in a register |
2185 | | } |
2186 | | */ |
2187 | 17 | if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) { |
2188 | 1 | S.Diag(AL.getLoc(), diag::err_repeat_attribute) << A; |
2189 | 1 | return; |
2190 | 1 | } |
2191 | | |
2192 | 16 | const auto *R = cast<RecordDecl>(D); |
2193 | 16 | int count = 0; |
2194 | | |
2195 | 16 | if (!isa<CXXRecordDecl>(R)) { |
2196 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); |
2197 | 0 | return; |
2198 | 0 | } |
2199 | | |
2200 | 16 | if (!cast<CXXRecordDecl>(R)->isPOD()) { |
2201 | 5 | S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_pod_record); |
2202 | 5 | return; |
2203 | 5 | } |
2204 | | |
2205 | 16 | for (const auto *I : R->fields())11 { |
2206 | 16 | if ((count == 1) || !I->getType()->isVectorType()11 ) { |
2207 | 5 | S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); |
2208 | 5 | return; |
2209 | 5 | } |
2210 | 11 | count++; |
2211 | 11 | } |
2212 | | |
2213 | 6 | D->addAttr(::new (S.Context) VecReturnAttr(S.Context, AL)); |
2214 | 6 | } |
2215 | | |
2216 | | static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, |
2217 | 27 | const ParsedAttr &AL) { |
2218 | 27 | if (isa<ParmVarDecl>(D)) { |
2219 | | // [[carries_dependency]] can only be applied to a parameter if it is a |
2220 | | // parameter of a function declaration or lambda. |
2221 | 14 | if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) { |
2222 | 6 | S.Diag(AL.getLoc(), |
2223 | 6 | diag::err_carries_dependency_param_not_function_decl); |
2224 | 6 | return; |
2225 | 6 | } |
2226 | 21 | } |
2227 | | |
2228 | 21 | D->addAttr(::new (S.Context) CarriesDependencyAttr(S.Context, AL)); |
2229 | 21 | } |
2230 | | |
2231 | 141k | static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2232 | 141k | bool IsCXX17Attr = AL.isCXX11Attribute() && !AL.getScopeName()25 ; |
2233 | | |
2234 | | // If this is spelled as the standard C++17 attribute, but not in C++17, warn |
2235 | | // about using it as an extension. |
2236 | 141k | if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr140k ) |
2237 | 5 | S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; |
2238 | | |
2239 | 141k | D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL)); |
2240 | 141k | } |
2241 | | |
2242 | 37 | static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2243 | 37 | uint32_t priority = ConstructorAttr::DefaultPriority; |
2244 | 37 | if (AL.getNumArgs() && |
2245 | 19 | !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) |
2246 | 4 | return; |
2247 | | |
2248 | 33 | D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); |
2249 | 33 | } |
2250 | | |
2251 | 48 | static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2252 | 48 | uint32_t priority = DestructorAttr::DefaultPriority; |
2253 | 48 | if (AL.getNumArgs() && |
2254 | 35 | !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) |
2255 | 1 | return; |
2256 | | |
2257 | 47 | D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority)); |
2258 | 47 | } |
2259 | | |
2260 | | template <typename AttrTy> |
2261 | 7.11k | static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) { |
2262 | | // Handle the case where the attribute has a text message. |
2263 | 7.11k | StringRef Str; |
2264 | 7.11k | if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str)1.61k ) |
2265 | 1 | return; |
2266 | | |
2267 | 7.10k | D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str)); |
2268 | 7.10k | } |
2269 | | |
2270 | | static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, |
2271 | 88 | const ParsedAttr &AL) { |
2272 | 88 | if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) { |
2273 | 1 | S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) |
2274 | 1 | << AL << AL.getRange(); |
2275 | 1 | return; |
2276 | 1 | } |
2277 | | |
2278 | 87 | D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL)); |
2279 | 87 | } |
2280 | | |
2281 | | static bool checkAvailabilityAttr(Sema &S, SourceRange Range, |
2282 | | IdentifierInfo *Platform, |
2283 | | VersionTuple Introduced, |
2284 | | VersionTuple Deprecated, |
2285 | 7.99M | VersionTuple Obsoleted) { |
2286 | 7.99M | StringRef PlatformName |
2287 | 7.99M | = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); |
2288 | 7.99M | if (PlatformName.empty()) |
2289 | 67.5k | PlatformName = Platform->getName(); |
2290 | | |
2291 | | // Ensure that Introduced <= Deprecated <= Obsoleted (although not all |
2292 | | // of these steps are needed). |
2293 | 7.99M | if (!Introduced.empty() && !Deprecated.empty()6.28M && |
2294 | 1.37M | !(Introduced <= Deprecated)) { |
2295 | 7 | S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) |
2296 | 7 | << 1 << PlatformName << Deprecated.getAsString() |
2297 | 7 | << 0 << Introduced.getAsString(); |
2298 | 7 | return true; |
2299 | 7 | } |
2300 | | |
2301 | 7.99M | if (!Introduced.empty() && !Obsoleted.empty()6.28M && |
2302 | 31 | !(Introduced <= Obsoleted)) { |
2303 | 0 | S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) |
2304 | 0 | << 2 << PlatformName << Obsoleted.getAsString() |
2305 | 0 | << 0 << Introduced.getAsString(); |
2306 | 0 | return true; |
2307 | 0 | } |
2308 | | |
2309 | 7.99M | if (!Deprecated.empty() && !Obsoleted.empty()1.43M && |
2310 | 28 | !(Deprecated <= Obsoleted)) { |
2311 | 3 | S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) |
2312 | 3 | << 2 << PlatformName << Obsoleted.getAsString() |
2313 | 3 | << 1 << Deprecated.getAsString(); |
2314 | 3 | return true; |
2315 | 3 | } |
2316 | | |
2317 | 7.99M | return false; |
2318 | 7.99M | } |
2319 | | |
2320 | | /// Check whether the two versions match. |
2321 | | /// |
2322 | | /// If either version tuple is empty, then they are assumed to match. If |
2323 | | /// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y. |
2324 | | static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y, |
2325 | 549k | bool BeforeIsOkay) { |
2326 | 549k | if (X.empty() || Y.empty()188k ) |
2327 | 368k | return true; |
2328 | | |
2329 | 180k | if (X == Y) |
2330 | 179k | return true; |
2331 | | |
2332 | 518 | if (BeforeIsOkay && X < Y98 ) |
2333 | 22 | return true; |
2334 | | |
2335 | 496 | return false; |
2336 | 496 | } |
2337 | | |
2338 | | AvailabilityAttr *Sema::mergeAvailabilityAttr( |
2339 | | NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform, |
2340 | | bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, |
2341 | | VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, |
2342 | | bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, |
2343 | 7.97M | int Priority) { |
2344 | 7.97M | VersionTuple MergedIntroduced = Introduced; |
2345 | 7.97M | VersionTuple MergedDeprecated = Deprecated; |
2346 | 7.97M | VersionTuple MergedObsoleted = Obsoleted; |
2347 | 7.97M | bool FoundAny = false; |
2348 | 7.97M | bool OverrideOrImpl = false; |
2349 | 7.97M | switch (AMK) { |
2350 | 7.75M | case AMK_None: |
2351 | 7.80M | case AMK_Redeclaration: |
2352 | 7.80M | OverrideOrImpl = false; |
2353 | 7.80M | break; |
2354 | | |
2355 | 176k | case AMK_Override: |
2356 | 178k | case AMK_ProtocolImplementation: |
2357 | 178k | OverrideOrImpl = true; |
2358 | 178k | break; |
2359 | 7.97M | } |
2360 | | |
2361 | 7.97M | if (D->hasAttrs()) { |
2362 | 5.39M | AttrVec &Attrs = D->getAttrs(); |
2363 | 16.1M | for (unsigned i = 0, e = Attrs.size(); i != e;) { |
2364 | 10.7M | const auto *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); |
2365 | 10.7M | if (!OldAA) { |
2366 | 1.26M | ++i; |
2367 | 1.26M | continue; |
2368 | 1.26M | } |
2369 | | |
2370 | 9.47M | IdentifierInfo *OldPlatform = OldAA->getPlatform(); |
2371 | 9.47M | if (OldPlatform != Platform) { |
2372 | 9.29M | ++i; |
2373 | 9.29M | continue; |
2374 | 9.29M | } |
2375 | | |
2376 | | // If there is an existing availability attribute for this platform that |
2377 | | // has a lower priority use the existing one and discard the new |
2378 | | // attribute. |
2379 | 183k | if (OldAA->getPriority() < Priority) |
2380 | 478 | return nullptr; |
2381 | | |
2382 | | // If there is an existing attribute for this platform that has a higher |
2383 | | // priority than the new attribute then erase the old one and continue |
2384 | | // processing the attributes. |
2385 | 183k | if (OldAA->getPriority() > Priority) { |
2386 | 80 | Attrs.erase(Attrs.begin() + i); |
2387 | 80 | --e; |
2388 | 80 | continue; |
2389 | 80 | } |
2390 | | |
2391 | 183k | FoundAny = true; |
2392 | 183k | VersionTuple OldIntroduced = OldAA->getIntroduced(); |
2393 | 183k | VersionTuple OldDeprecated = OldAA->getDeprecated(); |
2394 | 183k | VersionTuple OldObsoleted = OldAA->getObsoleted(); |
2395 | 183k | bool OldIsUnavailable = OldAA->getUnavailable(); |
2396 | | |
2397 | 183k | if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl) || |
2398 | 182k | !versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl) || |
2399 | 182k | !versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl) || |
2400 | 182k | !(OldIsUnavailable == IsUnavailable || |
2401 | 463 | (10 OverrideOrImpl10 && !OldIsUnavailable10 && IsUnavailable5 ))) { |
2402 | 463 | if (OverrideOrImpl) { |
2403 | 43 | int Which = -1; |
2404 | 43 | VersionTuple FirstVersion; |
2405 | 43 | VersionTuple SecondVersion; |
2406 | 43 | if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl)) { |
2407 | 33 | Which = 0; |
2408 | 33 | FirstVersion = OldIntroduced; |
2409 | 33 | SecondVersion = Introduced; |
2410 | 10 | } else if (!versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl)) { |
2411 | 5 | Which = 1; |
2412 | 5 | FirstVersion = Deprecated; |
2413 | 5 | SecondVersion = OldDeprecated; |
2414 | 5 | } else if (!versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl)) { |
2415 | 0 | Which = 2; |
2416 | 0 | FirstVersion = Obsoleted; |
2417 | 0 | SecondVersion = OldObsoleted; |
2418 | 0 | } |
2419 | | |
2420 | 43 | if (Which == -1) { |
2421 | 5 | Diag(OldAA->getLocation(), |
2422 | 5 | diag::warn_mismatched_availability_override_unavail) |
2423 | 5 | << AvailabilityAttr::getPrettyPlatformName(Platform->getName()) |
2424 | 5 | << (AMK == AMK_Override); |
2425 | 38 | } else { |
2426 | 38 | Diag(OldAA->getLocation(), |
2427 | 38 | diag::warn_mismatched_availability_override) |
2428 | 38 | << Which |
2429 | 38 | << AvailabilityAttr::getPrettyPlatformName(Platform->getName()) |
2430 | 38 | << FirstVersion.getAsString() << SecondVersion.getAsString() |
2431 | 38 | << (AMK == AMK_Override); |
2432 | 38 | } |
2433 | 43 | if (AMK == AMK_Override) |
2434 | 15 | Diag(CI.getLoc(), diag::note_overridden_method); |
2435 | 28 | else |
2436 | 28 | Diag(CI.getLoc(), diag::note_protocol_method); |
2437 | 420 | } else { |
2438 | 420 | Diag(OldAA->getLocation(), diag::warn_mismatched_availability); |
2439 | 420 | Diag(CI.getLoc(), diag::note_previous_attribute); |
2440 | 420 | } |
2441 | | |
2442 | 463 | Attrs.erase(Attrs.begin() + i); |
2443 | 463 | --e; |
2444 | 463 | continue; |
2445 | 463 | } |
2446 | | |
2447 | 182k | VersionTuple MergedIntroduced2 = MergedIntroduced; |
2448 | 182k | VersionTuple MergedDeprecated2 = MergedDeprecated; |
2449 | 182k | VersionTuple MergedObsoleted2 = MergedObsoleted; |
2450 | | |
2451 | 182k | if (MergedIntroduced2.empty()) |
2452 | 18.2k | MergedIntroduced2 = OldIntroduced; |
2453 | 182k | if (MergedDeprecated2.empty()) |
2454 | 150k | MergedDeprecated2 = OldDeprecated; |
2455 | 182k | if (MergedObsoleted2.empty()) |
2456 | 182k | MergedObsoleted2 = OldObsoleted; |
2457 | | |
2458 | 182k | if (checkAvailabilityAttr(*this, OldAA->getRange(), Platform, |
2459 | 182k | MergedIntroduced2, MergedDeprecated2, |
2460 | 4 | MergedObsoleted2)) { |
2461 | 4 | Attrs.erase(Attrs.begin() + i); |
2462 | 4 | --e; |
2463 | 4 | continue; |
2464 | 4 | } |
2465 | | |
2466 | 182k | MergedIntroduced = MergedIntroduced2; |
2467 | 182k | MergedDeprecated = MergedDeprecated2; |
2468 | 182k | MergedObsoleted = MergedObsoleted2; |
2469 | 182k | ++i; |
2470 | 182k | } |
2471 | 5.39M | } |
2472 | | |
2473 | 7.97M | if (FoundAny && |
2474 | 183k | MergedIntroduced == Introduced && |
2475 | 178k | MergedDeprecated == Deprecated && |
2476 | 166k | MergedObsoleted == Obsoleted) |
2477 | 166k | return nullptr; |
2478 | | |
2479 | | // Only create a new attribute if !OverrideOrImpl, but we want to do |
2480 | | // the checking. |
2481 | 7.81M | if (!checkAvailabilityAttr(*this, CI.getRange(), Platform, MergedIntroduced, |
2482 | 7.81M | MergedDeprecated, MergedObsoleted) && |
2483 | 7.81M | !OverrideOrImpl) { |
2484 | 7.79M | auto *Avail = ::new (Context) AvailabilityAttr( |
2485 | 7.79M | Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, |
2486 | 7.79M | Message, IsStrict, Replacement, Priority); |
2487 | 7.79M | Avail->setImplicit(Implicit); |
2488 | 7.79M | return Avail; |
2489 | 7.79M | } |
2490 | 13.9k | return nullptr; |
2491 | 13.9k | } |
2492 | | |
2493 | 7.75M | static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2494 | 7.75M | if (!checkAttributeNumArgs(S, AL, 1)) |
2495 | 0 | return; |
2496 | 7.75M | IdentifierLoc *Platform = AL.getArgAsIdent(0); |
2497 | | |
2498 | 7.75M | IdentifierInfo *II = Platform->Ident; |
2499 | 7.75M | if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) |
2500 | 67.5k | S.Diag(Platform->Loc, diag::warn_availability_unknown_platform) |
2501 | 67.5k | << Platform->Ident; |
2502 | | |
2503 | 7.75M | auto *ND = dyn_cast<NamedDecl>(D); |
2504 | 7.75M | if (!ND) // We warned about this already, so just return. |
2505 | 0 | return; |
2506 | | |
2507 | 7.75M | AvailabilityChange Introduced = AL.getAvailabilityIntroduced(); |
2508 | 7.75M | AvailabilityChange Deprecated = AL.getAvailabilityDeprecated(); |
2509 | 7.75M | AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted(); |
2510 | 7.75M | bool IsUnavailable = AL.getUnavailableLoc().isValid(); |
2511 | 7.75M | bool IsStrict = AL.getStrictLoc().isValid(); |
2512 | 7.75M | StringRef Str; |
2513 | 7.75M | if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getMessageExpr())) |
2514 | 676k | Str = SE->getString(); |
2515 | 7.75M | StringRef Replacement; |
2516 | 7.75M | if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr())) |
2517 | 106k | Replacement = SE->getString(); |
2518 | | |
2519 | 7.75M | if (II->isStr("swift")) { |
2520 | 42.0k | if (Introduced.isValid() || Obsoleted.isValid()42.0k || |
2521 | 42.0k | (!IsUnavailable && !Deprecated.isValid()3 )) { |
2522 | 2 | S.Diag(AL.getLoc(), |
2523 | 2 | diag::warn_availability_swift_unavailable_deprecated_only); |
2524 | 2 | return; |
2525 | 2 | } |
2526 | 7.75M | } |
2527 | | |
2528 | 7.75M | int PriorityModifier = AL.isPragmaClangAttribute() |
2529 | 63.9k | ? Sema::AP_PragmaClangAttribute |
2530 | 7.69M | : Sema::AP_Explicit; |
2531 | 7.75M | AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( |
2532 | 7.75M | ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version, |
2533 | 7.75M | Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement, |
2534 | 7.75M | Sema::AMK_None, PriorityModifier); |
2535 | 7.75M | if (NewAttr) |
2536 | 7.75M | D->addAttr(NewAttr); |
2537 | | |
2538 | | // Transcribe "ios" to "watchos" (and add a new attribute) if the versioning |
2539 | | // matches before the start of the watchOS platform. |
2540 | 7.75M | if (S.Context.getTargetInfo().getTriple().isWatchOS()) { |
2541 | 515 | IdentifierInfo *NewII = nullptr; |
2542 | 515 | if (II->getName() == "ios") |
2543 | 220 | NewII = &S.Context.Idents.get("watchos"); |
2544 | 295 | else if (II->getName() == "ios_app_extension") |
2545 | 0 | NewII = &S.Context.Idents.get("watchos_app_extension"); |
2546 | | |
2547 | 515 | if (NewII) { |
2548 | 660 | auto adjustWatchOSVersion = [](VersionTuple Version) -> VersionTuple { |
2549 | 660 | if (Version.empty()) |
2550 | 436 | return Version; |
2551 | 224 | auto Major = Version.getMajor(); |
2552 | 188 | auto NewMajor = Major >= 9 ? Major - 736 : 0; |
2553 | 224 | if (NewMajor >= 2) { |
2554 | 36 | if (Version.getMinor().hasValue()) { |
2555 | 35 | if (Version.getSubminor().hasValue()) |
2556 | 0 | return VersionTuple(NewMajor, Version.getMinor().getValue(), |
2557 | 0 | Version.getSubminor().getValue()); |
2558 | 35 | else |
2559 | 35 | return VersionTuple(NewMajor, Version.getMinor().getValue()); |
2560 | 1 | } |
2561 | 1 | return VersionTuple(NewMajor); |
2562 | 1 | } |
2563 | | |
2564 | 188 | return VersionTuple(2, 0); |
2565 | 188 | }; |
2566 | | |
2567 | 220 | auto NewIntroduced = adjustWatchOSVersion(Introduced.Version); |
2568 | 220 | auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); |
2569 | 220 | auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); |
2570 | | |
2571 | 220 | AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( |
2572 | 220 | ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, |
2573 | 220 | NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, |
2574 | 220 | Sema::AMK_None, |
2575 | 220 | PriorityModifier + Sema::AP_InferredFromOtherPlatform); |
2576 | 220 | if (NewAttr) |
2577 | 218 | D->addAttr(NewAttr); |
2578 | 220 | } |
2579 | 7.75M | } else if (S.Context.getTargetInfo().getTriple().isTvOS()) { |
2580 | | // Transcribe "ios" to "tvos" (and add a new attribute) if the versioning |
2581 | | // matches before the start of the tvOS platform. |
2582 | 544 | IdentifierInfo *NewII = nullptr; |
2583 | 544 | if (II->getName() == "ios") |
2584 | 221 | NewII = &S.Context.Idents.get("tvos"); |
2585 | 323 | else if (II->getName() == "ios_app_extension") |
2586 | 3 | NewII = &S.Context.Idents.get("tvos_app_extension"); |
2587 | | |
2588 | 544 | if (NewII) { |
2589 | 224 | AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( |
2590 | 224 | ND, AL, NewII, true /*Implicit*/, Introduced.Version, |
2591 | 224 | Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, |
2592 | 224 | Replacement, Sema::AMK_None, |
2593 | 224 | PriorityModifier + Sema::AP_InferredFromOtherPlatform); |
2594 | 224 | if (NewAttr) |
2595 | 217 | D->addAttr(NewAttr); |
2596 | 224 | } |
2597 | 544 | } |
2598 | 7.75M | } |
2599 | | |
2600 | | static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, |
2601 | 71 | const ParsedAttr &AL) { |
2602 | 71 | if (!checkAttributeAtLeastNumArgs(S, AL, 1)) |
2603 | 3 | return; |
2604 | 68 | assert(checkAttributeAtMostNumArgs(S, AL, 3) && |
2605 | 68 | "Invalid number of arguments in an external_source_symbol attribute"); |
2606 | | |
2607 | 68 | StringRef Language; |
2608 | 68 | if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(0))) |
2609 | 57 | Language = SE->getString(); |
2610 | 68 | StringRef DefinedIn; |
2611 | 68 | if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1))) |
2612 | 55 | DefinedIn = SE->getString(); |
2613 | 68 | bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; |
2614 | | |
2615 | 68 | D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( |
2616 | 68 | S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration)); |
2617 | 68 | } |
2618 | | |
2619 | | template <class T> |
2620 | | static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI, |
2621 | 1.87M | typename T::VisibilityType value) { |
2622 | 1.87M | T *existingAttr = D->getAttr<T>(); |
2623 | 1.87M | if (existingAttr) { |
2624 | 37.6k | typename T::VisibilityType existingValue = existingAttr->getVisibility(); |
2625 | 37.6k | if (existingValue == value) |
2626 | 37.6k | return nullptr; |
2627 | 6 | S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); |
2628 | 6 | S.Diag(CI.getLoc(), diag::note_previous_attribute); |
2629 | 6 | D->dropAttr<T>(); |
2630 | 6 | } |
2631 | 1.83M | return ::new (S.Context) T(S.Context, CI, value); |
2632 | 1.87M | } SemaDeclAttr.cpp:clang::VisibilityAttr* mergeVisibilityAttr<clang::VisibilityAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, clang::VisibilityAttr::VisibilityType) Line | Count | Source | 2621 | 1.71M | typename T::VisibilityType value) { | 2622 | 1.71M | T *existingAttr = D->getAttr<T>(); | 2623 | 1.71M | if (existingAttr) { | 2624 | 28.1k | typename T::VisibilityType existingValue = existingAttr->getVisibility(); | 2625 | 28.1k | if (existingValue == value) | 2626 | 28.1k | return nullptr; | 2627 | 6 | S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); | 2628 | 6 | S.Diag(CI.getLoc(), diag::note_previous_attribute); | 2629 | 6 | D->dropAttr<T>(); | 2630 | 6 | } | 2631 | 1.68M | return ::new (S.Context) T(S.Context, CI, value); | 2632 | 1.71M | } |
SemaDeclAttr.cpp:clang::TypeVisibilityAttr* mergeVisibilityAttr<clang::TypeVisibilityAttr>(clang::Sema&, clang::Decl*, clang::AttributeCommonInfo const&, clang::TypeVisibilityAttr::VisibilityType) Line | Count | Source | 2621 | 161k | typename T::VisibilityType value) { | 2622 | 161k | T *existingAttr = D->getAttr<T>(); | 2623 | 161k | if (existingAttr) { | 2624 | 9.48k | typename T::VisibilityType existingValue = existingAttr->getVisibility(); | 2625 | 9.48k | if (existingValue == value) | 2626 | 9.48k | return nullptr; | 2627 | 0 | S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); | 2628 | 0 | S.Diag(CI.getLoc(), diag::note_previous_attribute); | 2629 | 0 | D->dropAttr<T>(); | 2630 | 0 | } | 2631 | 152k | return ::new (S.Context) T(S.Context, CI, value); | 2632 | 161k | } |
|
2633 | | |
2634 | | VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, |
2635 | | const AttributeCommonInfo &CI, |
2636 | 1.71M | VisibilityAttr::VisibilityType Vis) { |
2637 | 1.71M | return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, CI, Vis); |
2638 | 1.71M | } |
2639 | | |
2640 | | TypeVisibilityAttr * |
2641 | | Sema::mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, |
2642 | 161k | TypeVisibilityAttr::VisibilityType Vis) { |
2643 | 161k | return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, CI, Vis); |
2644 | 161k | } |
2645 | | |
2646 | | static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, |
2647 | 1.75M | bool isTypeVisibility) { |
2648 | | // Visibility attributes don't mean anything on a typedef. |
2649 | 1.75M | if (isa<TypedefNameDecl>(D)) { |
2650 | 1 | S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL; |
2651 | 1 | return; |
2652 | 1 | } |
2653 | | |
2654 | | // 'type_visibility' can only go on a type or namespace. |
2655 | 1.75M | if (isTypeVisibility && |
2656 | 144k | !(isa<TagDecl>(D) || |
2657 | 1 | isa<ObjCInterfaceDecl>(D) || |
2658 | 1 | isa<NamespaceDecl>(D))) { |
2659 | 1 | S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) |
2660 | 1 | << AL << ExpectedTypeOrNamespace; |
2661 | 1 | return; |
2662 | 1 | } |
2663 | | |
2664 | | // Check that the argument is a string literal. |
2665 | 1.75M | StringRef TypeStr; |
2666 | 1.75M | SourceLocation LiteralLoc; |
2667 | 1.75M | if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc)) |
2668 | 0 | return; |
2669 | | |
2670 | 1.75M | VisibilityAttr::VisibilityType type; |
2671 | 1.75M | if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) { |
2672 | 0 | S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << AL |
2673 | 0 | << TypeStr; |
2674 | 0 | return; |
2675 | 0 | } |
2676 | | |
2677 | | // Complain about attempts to use protected visibility on targets |
2678 | | // (like Darwin) that don't support it. |
2679 | 1.75M | if (type == VisibilityAttr::Protected && |
2680 | 68 | !S.Context.getTargetInfo().hasProtectedVisibility()) { |
2681 | 3 | S.Diag(AL.getLoc(), diag::warn_attribute_protected_visibility); |
2682 | 3 | type = VisibilityAttr::Default; |
2683 | 3 | } |
2684 | | |
2685 | 1.75M | Attr *newAttr; |
2686 | 1.75M | if (isTypeVisibility) { |
2687 | 144k | newAttr = S.mergeTypeVisibilityAttr( |
2688 | 144k | D, AL, (TypeVisibilityAttr::VisibilityType)type); |
2689 | 1.60M | } else { |
2690 | 1.60M | newAttr = S.mergeVisibilityAttr(D, AL, type); |
2691 | 1.60M | } |
2692 | 1.75M | if (newAttr) |
2693 | 1.75M | D->addAttr(newAttr); |
2694 | 1.75M | } |
2695 | | |
2696 | | static void handleObjCNonRuntimeProtocolAttr(Sema &S, Decl *D, |
2697 | 21 | const ParsedAttr &AL) { |
2698 | 21 | handleSimpleAttribute<ObjCNonRuntimeProtocolAttr>(S, D, AL); |
2699 | 21 | } |
2700 | | |
2701 | 112 | static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2702 | | // objc_direct cannot be set on methods declared in the context of a protocol |
2703 | 112 | if (isa<ObjCProtocolDecl>(D->getDeclContext())) { |
2704 | 2 | S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false; |
2705 | 2 | return; |
2706 | 2 | } |
2707 | | |
2708 | 110 | if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { |
2709 | 110 | handleSimpleAttribute<ObjCDirectAttr>(S, D, AL); |
2710 | 0 | } else { |
2711 | 0 | S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; |
2712 | 0 | } |
2713 | 110 | } |
2714 | | |
2715 | | static void handleObjCDirectMembersAttr(Sema &S, Decl *D, |
2716 | 10 | const ParsedAttr &AL) { |
2717 | 10 | if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { |
2718 | 10 | handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL); |
2719 | 0 | } else { |
2720 | 0 | S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; |
2721 | 0 | } |
2722 | 10 | } |
2723 | | |
2724 | 18 | static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2725 | 18 | const auto *M = cast<ObjCMethodDecl>(D); |
2726 | 18 | if (!AL.isArgIdent(0)) { |
2727 | 2 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
2728 | 2 | << AL << 1 << AANT_ArgumentIdentifier; |
2729 | 2 | return; |
2730 | 2 | } |
2731 | | |
2732 | 16 | IdentifierLoc *IL = AL.getArgAsIdent(0); |
2733 | 16 | ObjCMethodFamilyAttr::FamilyKind F; |
2734 | 16 | if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) { |
2735 | 0 | S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident; |
2736 | 0 | return; |
2737 | 0 | } |
2738 | | |
2739 | 16 | if (F == ObjCMethodFamilyAttr::OMF_init && |
2740 | 14 | !M->getReturnType()->isObjCObjectPointerType()) { |
2741 | 0 | S.Diag(M->getLocation(), diag::err_init_method_bad_return_type) |
2742 | 0 | << M->getReturnType(); |
2743 | | // Ignore the attribute. |
2744 | 0 | return; |
2745 | 0 | } |
2746 | | |
2747 | 16 | D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F)); |
2748 | 16 | } |
2749 | | |
2750 | 15 | static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { |
2751 | 15 | if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { |
2752 | 9 | QualType T = TD->getUnderlyingType(); |
2753 | 9 | if (!T->isCARCBridgableType()) { |
2754 | 1 | S.Diag(TD->getLocation(), diag::err_nsobject_attribute); |
2755 | 1 | return; |
2756 | 1 | } |
2757 | 6 | } |
2758 | 6 | else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { |
2759 | 4 | QualType T = PD->getType(); |
2760 | 4 | if (!T->isCARCBridgableType()) { |
2761 | 1 | S.Diag(PD->getLocation(), diag::err_nsobject_attribute); |
2762 | 1 | return; |
2763 | 1 | } |
2764 | 2 | } |
2765 | 2 | else { |
2766 | | // It is okay to include this attribute on properties, e.g.: |
2767 | | // |
2768 | | // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); |
2769 | | // |
2770 | | // In this case it follows tradition and suppresses an error in the above |
2771 | | // case. |
2772 | 2 | S.Diag(D->getLocation(), diag::warn_nsobject_attribute); |
2773 | 2 | } |
2774 | 13 | D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL)); |
2775 | 13 | } |
2776 | | |
2777 | 5.83k | static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { |
2778 | 5.83k | if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { |
2779 | 5.83k | QualType T = TD->getUnderlyingType(); |
2780 | 5.83k | if (!T->isObjCObjectPointerType()) { |
2781 | 1 | S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); |
2782 | 1 | return; |
2783 | 1 | } |
2784 | 4 | } else { |
2785 | 4 | S.Diag(D->getLocation(), diag::warn_independentclass_attribute); |
2786 | 4 | return; |
2787 | 4 | } |
2788 | 5.83k | D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL)); |
2789 | 5.83k | } |
2790 | | |
2791 | 435 | static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2792 | 435 | if (!AL.isArgIdent(0)) { |
2793 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
2794 | 0 | << AL << 1 << AANT_ArgumentIdentifier; |
2795 | 0 | return; |
2796 | 0 | } |
2797 | | |
2798 | 435 | IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; |
2799 | 435 | BlocksAttr::BlockType type; |
2800 | 435 | if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { |
2801 | 0 | S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; |
2802 | 0 | return; |
2803 | 0 | } |
2804 | | |
2805 | 435 | D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type)); |
2806 | 435 | } |
2807 | | |
2808 | 2.55k | static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2809 | 2.55k | unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; |
2810 | 2.55k | if (AL.getNumArgs() > 0) { |
2811 | 2.51k | Expr *E = AL.getArgAsExpr(0); |
2812 | 2.51k | Optional<llvm::APSInt> Idx = llvm::APSInt(32); |
2813 | 2.51k | if (E->isTypeDependent() || E->isValueDependent() || |
2814 | 2.51k | !(Idx = E->getIntegerConstantExpr(S.Context))) { |
2815 | 4 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
2816 | 4 | << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); |
2817 | 4 | return; |
2818 | 4 | } |
2819 | | |
2820 | 2.51k | if (Idx->isSigned() && Idx->isNegative()) { |
2821 | 4 | S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero) |
2822 | 4 | << E->getSourceRange(); |
2823 | 4 | return; |
2824 | 4 | } |
2825 | | |
2826 | 2.50k | sentinel = Idx->getZExtValue(); |
2827 | 2.50k | } |
2828 | | |
2829 | 2.54k | unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; |
2830 | 2.54k | if (AL.getNumArgs() > 1) { |
2831 | 2.46k | Expr *E = AL.getArgAsExpr(1); |
2832 | 2.46k | Optional<llvm::APSInt> Idx = llvm::APSInt(32); |
2833 | 2.46k | if (E->isTypeDependent() || E->isValueDependent() || |
2834 | 2.46k | !(Idx = E->getIntegerConstantExpr(S.Context))) { |
2835 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
2836 | 0 | << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); |
2837 | 0 | return; |
2838 | 0 | } |
2839 | 2.46k | nullPos = Idx->getZExtValue(); |
2840 | | |
2841 | 2.46k | if ((Idx->isSigned() && Idx->isNegative()) || nullPos > 1) { |
2842 | | // FIXME: This error message could be improved, it would be nice |
2843 | | // to say what the bounds actually are. |
2844 | 3 | S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) |
2845 | 3 | << E->getSourceRange(); |
2846 | 3 | return; |
2847 | 3 | } |
2848 | 2.54k | } |
2849 | | |
2850 | 2.54k | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
2851 | 61 | const FunctionType *FT = FD->getType()->castAs<FunctionType>(); |
2852 | 61 | if (isa<FunctionNoProtoType>(FT)) { |
2853 | 2 | S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_named_arguments); |
2854 | 2 | return; |
2855 | 2 | } |
2856 | | |
2857 | 59 | if (!cast<FunctionProtoType>(FT)->isVariadic()) { |
2858 | 4 | S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; |
2859 | 4 | return; |
2860 | 4 | } |
2861 | 2.47k | } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { |
2862 | 2.46k | if (!MD->isVariadic()) { |
2863 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; |
2864 | 1 | return; |
2865 | 1 | } |
2866 | 16 | } else if (const auto *BD = dyn_cast<BlockDecl>(D)) { |
2867 | 4 | if (!BD->isVariadic()) { |
2868 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; |
2869 | 1 | return; |
2870 | 1 | } |
2871 | 12 | } else if (const auto *V = dyn_cast<VarDecl>(D)) { |
2872 | 12 | QualType Ty = V->getType(); |
2873 | 12 | if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()7 ) { |
2874 | 9 | const FunctionType *FT = Ty->isFunctionPointerType() |
2875 | 4 | ? D->getFunctionType() |
2876 | 5 | : Ty->castAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); |
2877 | 9 | if (!cast<FunctionProtoType>(FT)->isVariadic()) { |
2878 | 1 | int m = Ty->isFunctionPointerType() ? 00 : 1; |
2879 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; |
2880 | 1 | return; |
2881 | 1 | } |
2882 | 3 | } else { |
2883 | 3 | S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) |
2884 | 3 | << AL << ExpectedFunctionMethodOrBlock; |
2885 | 3 | return; |
2886 | 3 | } |
2887 | 0 | } else { |
2888 | 0 | S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) |
2889 | 0 | << AL << ExpectedFunctionMethodOrBlock; |
2890 | 0 | return; |
2891 | 0 | } |
2892 | 2.52k | D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos)); |
2893 | 2.52k | } |
2894 | | |
2895 | 48.3k | static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { |
2896 | 48.3k | if (D->getFunctionType() && |
2897 | 48.2k | D->getFunctionType()->getReturnType()->isVoidType() && |
2898 | 10 | !isa<CXXConstructorDecl>(D)) { |
2899 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0; |
2900 | 1 | return; |
2901 | 1 | } |
2902 | 48.3k | if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) |
2903 | 64 | if (MD->getReturnType()->isVoidType()) { |
2904 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 1; |
2905 | 1 | return; |
2906 | 1 | } |
2907 | | |
2908 | 48.3k | StringRef Str; |
2909 | 48.3k | if ((AL.isCXX11Attribute() || AL.isC2xAttribute()48.2k ) && !AL.getScopeName()100 ) { |
2910 | | // The standard attribute cannot be applied to variable declarations such |
2911 | | // as a function pointer. |
2912 | 86 | if (isa<VarDecl>(D)) |
2913 | 5 | S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) |
2914 | 5 | << AL << "functions, classes, or enumerations"; |
2915 | | |
2916 | | // If this is spelled as the standard C++17 attribute, but not in C++17, |
2917 | | // warn about using it as an extension. If there are attribute arguments, |
2918 | | // then claim it's a C++2a extension instead. |
2919 | | // FIXME: If WG14 does not seem likely to adopt the same feature, add an |
2920 | | // extension warning for C2x mode. |
2921 | 86 | const LangOptions &LO = S.getLangOpts(); |
2922 | 86 | if (AL.getNumArgs() == 1) { |
2923 | 29 | if (LO.CPlusPlus && !LO.CPlusPlus2028 ) |
2924 | 18 | S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL; |
2925 | | |
2926 | | // Since this this is spelled [[nodiscard]], get the optional string |
2927 | | // literal. If in C++ mode, but not in C++2a mode, diagnose as an |
2928 | | // extension. |
2929 | | // FIXME: C2x should support this feature as well, even as an extension. |
2930 | 29 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr)) |
2931 | 0 | return; |
2932 | 57 | } else if (LO.CPlusPlus && !LO.CPlusPlus1746 ) |
2933 | 13 | S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; |
2934 | 86 | } |
2935 | | |
2936 | 48.3k | D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str)); |
2937 | 48.3k | } |
2938 | | |
2939 | 979 | static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
2940 | | // weak_import only applies to variable & function declarations. |
2941 | 979 | bool isDef = false; |
2942 | 979 | if (!D->canBeWeakImported(isDef)) { |
2943 | 9 | if (isDef) |
2944 | 3 | S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition) |
2945 | 3 | << "weak_import"; |
2946 | 6 | else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)5 || |
2947 | 3 | (S.Context.getTargetInfo().getTriple().isOSDarwin() && |
2948 | 5 | (3 isa<ObjCInterfaceDecl>(D)3 || isa<EnumDecl>(D)3 ))) { |
2949 | | // Nothing to warn about here. |
2950 | 5 | } else |
2951 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) |
2952 | 1 | << AL << ExpectedVariableOrFunction; |
2953 | | |
2954 | 9 | return; |
2955 | 9 | } |
2956 | | |
2957 | 970 | D->addAttr(::new (S.Context) WeakImportAttr(S.Context, AL)); |
2958 | 970 | } |
2959 | | |
2960 | | // Handles reqd_work_group_size and work_group_size_hint. |
2961 | | template <typename WorkGroupAttr> |
2962 | 20 | static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { |
2963 | 20 | uint32_t WGSize[3]; |
2964 | 71 | for (unsigned i = 0; i < 3; ++i51 ) { |
2965 | 56 | const Expr *E = AL.getArgAsExpr(i); |
2966 | 56 | if (!checkUInt32Argument(S, AL, E, WGSize[i], i, |
2967 | 56 | /*StrictlyUnsigned=*/true)) |
2968 | 2 | return; |
2969 | 54 | if (WGSize[i] == 0) { |
2970 | 3 | S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) |
2971 | 3 | << AL << E->getSourceRange(); |
2972 | 3 | return; |
2973 | 3 | } |
2974 | 54 | } |
2975 | | |
2976 | 15 | WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>(); |
2977 | 15 | if (Existing && !(1 Existing->getXDim() == WGSize[0]1 && |
2978 | 0 | Existing->getYDim() == WGSize[1] && |
2979 | 0 | Existing->getZDim() == WGSize[2])) |
2980 | 1 | S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; |
2981 | | |
2982 | 15 | D->addAttr(::new (S.Context) |
2983 | 15 | WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2])); |
2984 | 15 | } SemaDeclAttr.cpp:void handleWorkGroupSize<clang::WorkGroupSizeHintAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 2962 | 6 | static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { | 2963 | 6 | uint32_t WGSize[3]; | 2964 | 22 | for (unsigned i = 0; i < 3; ++i16 ) { | 2965 | 17 | const Expr *E = AL.getArgAsExpr(i); | 2966 | 17 | if (!checkUInt32Argument(S, AL, E, WGSize[i], i, | 2967 | 17 | /*StrictlyUnsigned=*/true)) | 2968 | 1 | return; | 2969 | 16 | if (WGSize[i] == 0) { | 2970 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) | 2971 | 0 | << AL << E->getSourceRange(); | 2972 | 0 | return; | 2973 | 0 | } | 2974 | 16 | } | 2975 | | | 2976 | 5 | WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>(); | 2977 | 5 | if (Existing && !(1 Existing->getXDim() == WGSize[0]1 && | 2978 | 0 | Existing->getYDim() == WGSize[1] && | 2979 | 0 | Existing->getZDim() == WGSize[2])) | 2980 | 1 | S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; | 2981 | | | 2982 | 5 | D->addAttr(::new (S.Context) | 2983 | 5 | WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2])); | 2984 | 5 | } |
SemaDeclAttr.cpp:void handleWorkGroupSize<clang::ReqdWorkGroupSizeAttr>(clang::Sema&, clang::Decl*, clang::ParsedAttr const&) Line | Count | Source | 2962 | 14 | static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { | 2963 | 14 | uint32_t WGSize[3]; | 2964 | 49 | for (unsigned i = 0; i < 3; ++i35 ) { | 2965 | 39 | const Expr *E = AL.getArgAsExpr(i); | 2966 | 39 | if (!checkUInt32Argument(S, AL, E, WGSize[i], i, | 2967 | 39 | /*StrictlyUnsigned=*/true)) | 2968 | 1 | return; | 2969 | 38 | if (WGSize[i] == 0) { | 2970 | 3 | S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) | 2971 | 3 | << AL << E->getSourceRange(); | 2972 | 3 | return; | 2973 | 3 | } | 2974 | 38 | } | 2975 | | | 2976 | 10 | WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>(); | 2977 | 10 | if (Existing && !(0 Existing->getXDim() == WGSize[0]0 && | 2978 | 0 | Existing->getYDim() == WGSize[1] && | 2979 | 0 | Existing->getZDim() == WGSize[2])) | 2980 | 0 | S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; | 2981 | | | 2982 | 10 | D->addAttr(::new (S.Context) | 2983 | 10 | WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2])); | 2984 | 10 | } |
|
2985 | | |
2986 | | // Handles intel_reqd_sub_group_size. |
2987 | 6 | static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { |
2988 | 6 | uint32_t SGSize; |
2989 | 6 | const Expr *E = AL.getArgAsExpr(0); |
2990 | 6 | if (!checkUInt32Argument(S, AL, E, SGSize)) |
2991 | 0 | return; |
2992 | 6 | if (SGSize == 0) { |
2993 | 1 | S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) |
2994 | 1 | << AL << E->getSourceRange(); |
2995 | 1 | return; |
2996 | 1 | } |
2997 | | |
2998 | 5 | OpenCLIntelReqdSubGroupSizeAttr *Existing = |
2999 | 5 | D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); |
3000 | 5 | if (Existing && Existing->getSubGroupSize() != SGSize1 ) |
3001 | 1 | S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; |
3002 | | |
3003 | 5 | D->addAttr(::new (S.Context) |
3004 | 5 | OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize)); |
3005 | 5 | } |
3006 | | |
3007 | 8 | static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { |
3008 | 8 | if (!AL.hasParsedType()) { |
3009 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; |
3010 | 0 | return; |
3011 | 0 | } |
3012 | | |
3013 | 8 | TypeSourceInfo *ParmTSI = nullptr; |
3014 | 8 | QualType ParmType = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI); |
3015 | 8 | assert(ParmTSI && "no type source info for attribute argument"); |
3016 | | |
3017 | 8 | if (!ParmType->isExtVectorType() && !ParmType->isFloatingType()7 && |
3018 | 6 | (ParmType->isBooleanType() || |
3019 | 5 | !ParmType->isIntegralType(S.getASTContext()))) { |
3020 | 2 | S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 2 << AL; |
3021 | 2 | return; |
3022 | 2 | } |
3023 | | |
3024 | 6 | if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) { |
3025 | 1 | if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) { |
3026 | 1 | S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; |
3027 | 1 | return; |
3028 | 1 | } |
3029 | 5 | } |
3030 | | |
3031 | 5 | D->addAttr(::new (S.Context) VecTypeHintAttr(S.Context, AL, ParmTSI)); |
3032 | 5 | } |
3033 | | |
3034 | | SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI, |
3035 | 1.28k | StringRef Name) { |
3036 | | // Explicit or partial specializations do not inherit |
3037 | | // the section attribute from the primary template. |
3038 | 1.28k | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
3039 | 70 | if (CI.getAttributeSpellingListIndex() == SectionAttr::Declspec_allocate && |
3040 | 3 | FD->isFunctionTemplateSpecialization()) |
3041 | 3 | return nullptr; |
3042 | 1.27k | } |
3043 | 1.27k | if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) { |
3044 | 7 | if (ExistingAttr->getName() == Name) |
3045 | 0 | return nullptr; |
3046 | 7 | Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) |
3047 | 7 | << 1 /*section*/; |
3048 | 7 | Diag(CI.getLoc(), diag::note_previous_attribute); |
3049 | 7 | return nullptr; |
3050 | 7 | } |
3051 | 1.27k | return ::new (Context) SectionAttr(Context, CI, Name); |
3052 | 1.27k | } |
3053 | | |
3054 | 1.29k | bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { |
3055 | 1.29k | std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); |
3056 | 1.29k | if (!Error.empty()) { |
3057 | 2 | Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error |
3058 | 2 | << 1 /*'section'*/; |
3059 | 2 | return false; |
3060 | 2 | } |
3061 | 1.29k | return true; |
3062 | 1.29k | } |
3063 | | |
3064 | 1.25k | static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3065 | | // Make sure that there is a string literal as the sections's single |
3066 | | // argument. |
3067 | 1.25k | StringRef Str; |
3068 | 1.25k | SourceLocation LiteralLoc; |
3069 | 1.25k | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) |
3070 | 2 | return; |
3071 | | |
3072 | 1.25k | if (!S.checkSectionName(LiteralLoc, Str)) |
3073 | 1 | return; |
3074 | | |
3075 | | // If the target wants to validate the section specifier, make it happen. |
3076 | 1.25k | std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str); |
3077 | 1.25k | if (!Error.empty()) { |
3078 | 0 | S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) |
3079 | 0 | << Error; |
3080 | 0 | return; |
3081 | 0 | } |
3082 | | |
3083 | 1.25k | SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str); |
3084 | 1.25k | if (NewAttr) { |
3085 | 1.25k | D->addAttr(NewAttr); |
3086 | 1.25k | if (isa<FunctionDecl, FunctionTemplateDecl, ObjCMethodDecl, |
3087 | 1.25k | ObjCPropertyDecl>(D)) |
3088 | 52 | S.UnifySection(NewAttr->getName(), |
3089 | 52 | ASTContext::PSF_Execute | ASTContext::PSF_Read, |
3090 | 52 | cast<NamedDecl>(D)); |
3091 | 1.25k | } |
3092 | 1.25k | } |
3093 | | |
3094 | | // This is used for `__declspec(code_seg("segname"))` on a decl. |
3095 | | // `#pragma code_seg("segname")` uses checkSectionName() instead. |
3096 | | static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc, |
3097 | 82 | StringRef CodeSegName) { |
3098 | 82 | std::string Error = |
3099 | 82 | S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName); |
3100 | 82 | if (!Error.empty()) { |
3101 | 0 | S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) |
3102 | 0 | << Error << 0 /*'code-seg'*/; |
3103 | 0 | return false; |
3104 | 0 | } |
3105 | | |
3106 | 82 | return true; |
3107 | 82 | } |
3108 | | |
3109 | | CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI, |
3110 | 93 | StringRef Name) { |
3111 | | // Explicit or partial specializations do not inherit |
3112 | | // the code_seg attribute from the primary template. |
3113 | 93 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
3114 | 46 | if (FD->isFunctionTemplateSpecialization()) |
3115 | 3 | return nullptr; |
3116 | 90 | } |
3117 | 90 | if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { |
3118 | 14 | if (ExistingAttr->getName() == Name) |
3119 | 12 | return nullptr; |
3120 | 2 | Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) |
3121 | 2 | << 0 /*codeseg*/; |
3122 | 2 | Diag(CI.getLoc(), diag::note_previous_attribute); |
3123 | 2 | return nullptr; |
3124 | 2 | } |
3125 | 76 | return ::new (Context) CodeSegAttr(Context, CI, Name); |
3126 | 76 | } |
3127 | | |
3128 | 82 | static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3129 | 82 | StringRef Str; |
3130 | 82 | SourceLocation LiteralLoc; |
3131 | 82 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) |
3132 | 0 | return; |
3133 | 82 | if (!checkCodeSegName(S, LiteralLoc, Str)) |
3134 | 0 | return; |
3135 | 82 | if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { |
3136 | 14 | if (!ExistingAttr->isImplicit()) { |
3137 | 6 | S.Diag(AL.getLoc(), |
3138 | 6 | ExistingAttr->getName() == Str |
3139 | 3 | ? diag::warn_duplicate_codeseg_attribute |
3140 | 3 | : diag::err_conflicting_codeseg_attribute); |
3141 | 6 | return; |
3142 | 6 | } |
3143 | 8 | D->dropAttr<CodeSegAttr>(); |
3144 | 8 | } |
3145 | 76 | if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL, Str)) |
3146 | 76 | D->addAttr(CSA); |
3147 | 76 | } |
3148 | | |
3149 | | // Check for things we'd like to warn about. Multiversioning issues are |
3150 | | // handled later in the process, once we know how many exist. |
3151 | 1.09M | bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { |
3152 | 1.09M | enum FirstParam { Unsupported, Duplicate, Unknown }; |
3153 | 1.09M | enum SecondParam { None, Architecture, Tune }; |
3154 | 1.09M | if (AttrStr.find("fpmath=") != StringRef::npos) |
3155 | 2 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3156 | 2 | << Unsupported << None << "fpmath="; |
3157 | | |
3158 | | // Diagnose use of tune if target doesn't support it. |
3159 | 1.09M | if (!Context.getTargetInfo().supportsTargetAttributeTune() && |
3160 | 725 | AttrStr.find("tune=") != StringRef::npos) |
3161 | 1 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3162 | 1 | << Unsupported << None << "tune="; |
3163 | | |
3164 | 1.09M | ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); |
3165 | | |
3166 | 1.09M | if (!ParsedAttrs.Architecture.empty() && |
3167 | 158 | !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) |
3168 | 3 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3169 | 3 | << Unknown << Architecture << ParsedAttrs.Architecture; |
3170 | | |
3171 | 1.09M | if (!ParsedAttrs.Tune.empty() && |
3172 | 3 | !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune)) |
3173 | 1 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3174 | 1 | << Unknown << Tune << ParsedAttrs.Tune; |
3175 | | |
3176 | 1.09M | if (ParsedAttrs.DuplicateArchitecture) |
3177 | 1 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3178 | 1 | << Duplicate << None << "arch="; |
3179 | 1.09M | if (ParsedAttrs.DuplicateTune) |
3180 | 0 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3181 | 0 | << Duplicate << None << "tune="; |
3182 | | |
3183 | 1.28M | for (const auto &Feature : ParsedAttrs.Features)1.09M { |
3184 | 1.28M | auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. |
3185 | 1.28M | if (!Context.getTargetInfo().isValidFeatureName(CurFeature)) |
3186 | 4 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3187 | 4 | << Unsupported << None << CurFeature; |
3188 | 1.28M | } |
3189 | | |
3190 | 1.09M | TargetInfo::BranchProtectionInfo BPI; |
3191 | 1.09M | StringRef Error; |
3192 | 1.09M | if (!ParsedAttrs.BranchProtection.empty() && |
3193 | 19 | !Context.getTargetInfo().validateBranchProtection( |
3194 | 8 | ParsedAttrs.BranchProtection, BPI, Error)) { |
3195 | 8 | if (Error.empty()) |
3196 | 1 | return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) |
3197 | 1 | << Unsupported << None << "branch-protection"; |
3198 | 7 | else |
3199 | 7 | return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) |
3200 | 7 | << Error; |
3201 | 1.09M | } |
3202 | | |
3203 | 1.09M | return false; |
3204 | 1.09M | } |
3205 | | |
3206 | 1.09M | static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3207 | 1.09M | StringRef Str; |
3208 | 1.09M | SourceLocation LiteralLoc; |
3209 | 1.09M | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || |
3210 | 1.09M | S.checkTargetAttr(LiteralLoc, Str)) |
3211 | 20 | return; |
3212 | | |
3213 | 1.09M | TargetAttr *NewAttr = ::new (S.Context) TargetAttr(S.Context, AL, Str); |
3214 | 1.09M | D->addAttr(NewAttr); |
3215 | 1.09M | } |
3216 | | |
3217 | 1.04M | static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3218 | 1.04M | Expr *E = AL.getArgAsExpr(0); |
3219 | 1.04M | uint32_t VecWidth; |
3220 | 1.04M | if (!checkUInt32Argument(S, AL, E, VecWidth)) { |
3221 | 1 | AL.setInvalid(); |
3222 | 1 | return; |
3223 | 1 | } |
3224 | | |
3225 | 1.04M | MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>(); |
3226 | 1.04M | if (Existing && Existing->getVectorWidth() != VecWidth1 ) { |
3227 | 1 | S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; |
3228 | 1 | return; |
3229 | 1 | } |
3230 | | |
3231 | 1.04M | D->addAttr(::new (S.Context) MinVectorWidthAttr(S.Context, AL, VecWidth)); |
3232 | 1.04M | } |
3233 | | |
3234 | 37 | static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3235 | 37 | Expr *E = AL.getArgAsExpr(0); |
3236 | 37 | SourceLocation Loc = E->getExprLoc(); |
3237 | 37 | FunctionDecl *FD = nullptr; |
3238 | 37 | DeclarationNameInfo NI; |
3239 | | |
3240 | | // gcc only allows for simple identifiers. Since we support more than gcc, we |
3241 | | // will warn the user. |
3242 | 37 | if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { |
3243 | 34 | if (DRE->hasQualifier()) |
3244 | 4 | S.Diag(Loc, diag::warn_cleanup_ext); |
3245 | 34 | FD = dyn_cast<FunctionDecl>(DRE->getDecl()); |
3246 | 34 | NI = DRE->getNameInfo(); |
3247 | 34 | if (!FD) { |
3248 | 1 | S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 1 |
3249 | 1 | << NI.getName(); |
3250 | 1 | return; |
3251 | 1 | } |
3252 | 3 | } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { |
3253 | 2 | if (ULE->hasExplicitTemplateArgs()) |
3254 | 1 | S.Diag(Loc, diag::warn_cleanup_ext); |
3255 | 2 | FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); |
3256 | 2 | NI = ULE->getNameInfo(); |
3257 | 2 | if (!FD) { |
3258 | 1 | S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2 |
3259 | 1 | << NI.getName(); |
3260 | 1 | if (ULE->getType() == S.Context.OverloadTy) |
3261 | 1 | S.NoteAllOverloadCandidates(ULE); |
3262 | 1 | return; |
3263 | 1 | } |
3264 | 1 | } else { |
3265 | 1 | S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 0; |
3266 | 1 | return; |
3267 | 1 | } |
3268 | | |
3269 | 34 | if (FD->getNumParams() != 1) { |
3270 | 1 | S.Diag(Loc, diag::err_attribute_cleanup_func_must_take_one_arg) |
3271 | 1 | << NI.getName(); |
3272 | 1 | return; |
3273 | 1 | } |
3274 | | |
3275 | | // We're currently more strict than GCC about what function types we accept. |
3276 | | // If this ever proves to be a problem it should be easy to fix. |
3277 | 33 | QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType()); |
3278 | 33 | QualType ParamTy = FD->getParamDecl(0)->getType(); |
3279 | 33 | if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), |
3280 | 1 | ParamTy, Ty) != Sema::Compatible) { |
3281 | 1 | S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type) |
3282 | 1 | << NI.getName() << ParamTy << Ty; |
3283 | 1 | return; |
3284 | 1 | } |
3285 | | |
3286 | 32 | D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); |
3287 | 32 | } |
3288 | | |
3289 | | static void handleEnumExtensibilityAttr(Sema &S, Decl *D, |
3290 | 129k | const ParsedAttr &AL) { |
3291 | 129k | if (!AL.isArgIdent(0)) { |
3292 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
3293 | 0 | << AL << 0 << AANT_ArgumentIdentifier; |
3294 | 0 | return; |
3295 | 0 | } |
3296 | | |
3297 | 129k | EnumExtensibilityAttr::Kind ExtensibilityKind; |
3298 | 129k | IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; |
3299 | 129k | if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(), |
3300 | 1 | ExtensibilityKind)) { |
3301 | 1 | S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; |
3302 | 1 | return; |
3303 | 1 | } |
3304 | | |
3305 | 129k | D->addAttr(::new (S.Context) |
3306 | 129k | EnumExtensibilityAttr(S.Context, AL, ExtensibilityKind)); |
3307 | 129k | } |
3308 | | |
3309 | | /// Handle __attribute__((format_arg((idx)))) attribute based on |
3310 | | /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html |
3311 | 1.00k | static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3312 | 1.00k | Expr *IdxExpr = AL.getArgAsExpr(0); |
3313 | 1.00k | ParamIdx Idx; |
3314 | 1.00k | if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) |
3315 | 2 | return; |
3316 | | |
3317 | | // Make sure the format string is really a string. |
3318 | 1.00k | QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); |
3319 | | |
3320 | 1.00k | bool NotNSStringTy = !isNSStringType(Ty, S.Context); |
3321 | 1.00k | if (NotNSStringTy && |
3322 | 706 | !isCFStringType(Ty, S.Context) && |
3323 | 411 | (!Ty->isPointerType() || |
3324 | 409 | !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) { |
3325 | 2 | S.Diag(AL.getLoc(), diag::err_format_attribute_not) |
3326 | 2 | << "a string type" << IdxExpr->getSourceRange() |
3327 | 2 | << getFunctionOrMethodParamRange(D, 0); |
3328 | 2 | return; |
3329 | 2 | } |
3330 | 1.00k | Ty = getFunctionOrMethodResultType(D); |
3331 | 1.00k | if (!isNSStringType(Ty, S.Context) && |
3332 | 705 | !isCFStringType(Ty, S.Context) && |
3333 | 115 | (!Ty->isPointerType() || |
3334 | 114 | !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) { |
3335 | 1 | S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) |
3336 | 1 | << (NotNSStringTy ? "string type"0 : "NSString") |
3337 | 1 | << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); |
3338 | 1 | return; |
3339 | 1 | } |
3340 | | |
3341 | 1.00k | D->addAttr(::new (S.Context) FormatArgAttr(S.Context, AL, Idx)); |
3342 | 1.00k | } |
3343 | | |
3344 | | enum FormatAttrKind { |
3345 | | CFStringFormat, |
3346 | | NSStringFormat, |
3347 | | StrftimeFormat, |
3348 | | SupportedFormat, |
3349 | | IgnoredFormat, |
3350 | | InvalidFormat |
3351 | | }; |
3352 | | |
3353 | | /// getFormatAttrKind - Map from format attribute names to supported format |
3354 | | /// types. |
3355 | 37.4k | static FormatAttrKind getFormatAttrKind(StringRef Format) { |
3356 | 37.4k | return llvm::StringSwitch<FormatAttrKind>(Format) |
3357 | | // Check for formats that get handled specially. |
3358 | 37.4k | .Case("NSString", NSStringFormat) |
3359 | 37.4k | .Case("CFString", CFStringFormat) |
3360 | 37.4k | .Case("strftime", StrftimeFormat) |
3361 | | |
3362 | | // Otherwise, check for supported formats. |
3363 | 37.4k | .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat) |
3364 | 37.4k | .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat) |
3365 | 37.4k | .Case("kprintf", SupportedFormat) // OpenBSD. |
3366 | 37.4k | .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. |
3367 | 37.4k | .Case("os_trace", SupportedFormat) |
3368 | 37.4k | .Case("os_log", SupportedFormat) |
3369 | | |
3370 | 37.4k | .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat) |
3371 | 37.4k | .Default(InvalidFormat); |
3372 | 37.4k | } |
3373 | | |
3374 | | /// Handle __attribute__((init_priority(priority))) attributes based on |
3375 | | /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html |
3376 | 1.13k | static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3377 | 1.13k | if (!S.getLangOpts().CPlusPlus) { |
3378 | 0 | S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; |
3379 | 0 | return; |
3380 | 0 | } |
3381 | | |
3382 | 1.13k | if (S.getCurFunctionOrMethodDecl()) { |
3383 | 2 | S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); |
3384 | 2 | AL.setInvalid(); |
3385 | 2 | return; |
3386 | 2 | } |
3387 | 1.13k | QualType T = cast<VarDecl>(D)->getType(); |
3388 | 1.13k | if (S.Context.getAsArrayType(T)) |
3389 | 6 | T = S.Context.getBaseElementType(T); |
3390 | 1.13k | if (!T->getAs<RecordType>()) { |
3391 | 2 | S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); |
3392 | 2 | AL.setInvalid(); |
3393 | 2 | return; |
3394 | 2 | } |
3395 | | |
3396 | 1.13k | Expr *E = AL.getArgAsExpr(0); |
3397 | 1.13k | uint32_t prioritynum; |
3398 | 1.13k | if (!checkUInt32Argument(S, AL, E, prioritynum)) { |
3399 | 2 | AL.setInvalid(); |
3400 | 2 | return; |
3401 | 2 | } |
3402 | | |
3403 | | // Only perform the priority check if the attribute is outside of a system |
3404 | | // header. Values <= 100 are reserved for the implementation, and libc++ |
3405 | | // benefits from being able to specify values in that range. |
3406 | 1.13k | if ((prioritynum < 101 || prioritynum > 655351.12k ) && |
3407 | 4 | !S.getSourceManager().isInSystemHeader(AL.getLoc())) { |
3408 | 2 | S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) |
3409 | 2 | << E->getSourceRange() << AL << 101 << 65535; |
3410 | 2 | AL.setInvalid(); |
3411 | 2 | return; |
3412 | 2 | } |
3413 | 1.12k | D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum)); |
3414 | 1.12k | } |
3415 | | |
3416 | | FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, |
3417 | | IdentifierInfo *Format, int FormatIdx, |
3418 | 38.3k | int FirstArg) { |
3419 | | // Check whether we already have an equivalent format attribute. |
3420 | 408 | for (auto *F : D->specific_attrs<FormatAttr>()) { |
3421 | 408 | if (F->getType() == Format && |
3422 | 400 | F->getFormatIdx() == FormatIdx && |
3423 | 400 | F->getFirstArg() == FirstArg) { |
3424 | | // If we don't have a valid location for this attribute, adopt the |
3425 | | // location. |
3426 | 400 | if (F->getLocation().isInvalid()) |
3427 | 0 | F->setRange(CI.getRange()); |
3428 | 400 | return nullptr; |
3429 | 400 | } |
3430 | 408 | } |
3431 | | |
3432 | 37.9k | return ::new (Context) FormatAttr(Context, CI, Format, FormatIdx, FirstArg); |
3433 | 38.3k | } |
3434 | | |
3435 | | /// Handle __attribute__((format(type,idx,firstarg))) attributes based on |
3436 | | /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html |
3437 | 37.4k | static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3438 | 37.4k | if (!AL.isArgIdent(0)) { |
3439 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) |
3440 | 0 | << AL << 1 << AANT_ArgumentIdentifier; |
3441 | 0 | return; |
3442 | 0 | } |
3443 | | |
3444 | | // In C++ the implicit 'this' function parameter also counts, and they are |
3445 | | // counted from one. |
3446 | 37.4k | bool HasImplicitThisParam = isInstanceMethod(D); |
3447 | 37.4k | unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam; |
3448 | | |
3449 | 37.4k | IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; |
3450 | 37.4k | StringRef Format = II->getName(); |
3451 | | |
3452 | 37.4k | if (normalizeName(Format)) { |
3453 | | // If we've modified the string name, we need a new identifier for it. |
3454 | 34.8k | II = &S.Context.Idents.get(Format); |
3455 | 34.8k | } |
3456 | | |
3457 | | // Check for supported formats. |
3458 | 37.4k | FormatAttrKind Kind = getFormatAttrKind(Format); |
3459 | | |
3460 | 37.4k | if (Kind == IgnoredFormat) |
3461 | 4 | return; |
3462 | | |
3463 | 37.4k | if (Kind == InvalidFormat) { |
3464 | 0 | S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) |
3465 | 0 | << AL << II->getName(); |
3466 | 0 | return; |
3467 | 0 | } |
3468 | | |
3469 | | // checks for the 2nd argument |
3470 | 37.4k | Expr *IdxExpr = AL.getArgAsExpr(1); |
3471 | 37.4k | uint32_t Idx; |
3472 | 37.4k | if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2)) |
3473 | 0 | return; |
3474 | | |
3475 | 37.4k | if (Idx < 1 || Idx > NumArgs37.4k ) { |
3476 | 3 | S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) |
3477 | 3 | << AL << 2 << IdxExpr->getSourceRange(); |
3478 | 3 | return; |
3479 | 3 | } |
3480 | | |
3481 | | // FIXME: Do we need to bounds check? |
3482 | 37.4k | unsigned ArgIdx = Idx - 1; |
3483 | | |
3484 | 37.4k | if (HasImplicitThisParam) { |
3485 | 76 | if (ArgIdx == 0) { |
3486 | 4 | S.Diag(AL.getLoc(), |
3487 | 4 | diag::err_format_attribute_implicit_this_format_string) |
3488 | 4 | << IdxExpr->getSourceRange(); |
3489 | 4 | return; |
3490 | 4 | } |
3491 | 72 | ArgIdx--; |
3492 | 72 | } |
3493 | | |
3494 | | // make sure the format string is really a string |
3495 | 37.4k | QualType Ty = getFunctionOrMethodParamType(D, ArgIdx); |
3496 | | |
3497 | 37.4k | if (Kind == CFStringFormat) { |
3498 | 1.18k | if (!isCFStringType(Ty, S.Context)) { |
3499 | 1 | S.Diag(AL.getLoc(), diag::err_format_attribute_not) |
3500 | 1 | << "a CFString" << IdxExpr->getSourceRange() |
3501 | 1 | << getFunctionOrMethodParamRange(D, ArgIdx); |
3502 | 1 | return; |
3503 | 1 | } |
3504 | 36.2k | } else if (Kind == NSStringFormat) { |
3505 | | // FIXME: do we need to check if the type is NSString*? What are the |
3506 | | // semantics? |
3507 | 4.18k | if (!isNSStringType(Ty, S.Context)) { |
3508 | 1 | S.Diag(AL.getLoc(), diag::err_format_attribute_not) |
3509 | 1 | << "an NSString" << IdxExpr->getSourceRange() |
3510 | 1 | << getFunctionOrMethodParamRange(D, ArgIdx); |
3511 | 1 | return; |
3512 | 1 | } |
3513 | 32.0k | } else if (!Ty->isPointerType() || |
3514 | 32.0k | !Ty->castAs<PointerType>()->getPointeeType()->isCharType()) { |
3515 | 8 | S.Diag(AL.getLoc(), diag::err_format_attribute_not) |
3516 | 8 | << "a string type" << IdxExpr->getSourceRange() |
3517 | 8 | << getFunctionOrMethodParamRange(D, ArgIdx); |
3518 | 8 | return; |
3519 | 8 | } |
3520 | | |
3521 | | // check the 3rd argument |
3522 | 37.4k | Expr *FirstArgExpr = AL.getArgAsExpr(2); |
3523 | 37.4k | uint32_t FirstArg; |
3524 | 37.4k | if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) |
3525 | 0 | return; |
3526 | | |
3527 | | // check if the function is variadic if the 3rd argument non-zero |
3528 | 37.4k | if (FirstArg != 0) { |
3529 | 18.9k | if (isFunctionOrMethodVariadic(D)) { |
3530 | 18.9k | ++NumArgs; // +1 for ... |
3531 | 3 | } else { |
3532 | 3 | S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic); |
3533 | 3 | return; |
3534 | 3 | } |
3535 | 37.4k | } |
3536 | | |
3537 | | // strftime requires FirstArg to be 0 because it doesn't read from any |
3538 | | // variable the input is just the current time + the format string. |
3539 | 37.4k | if (Kind == StrftimeFormat) { |
3540 | 196 | if (FirstArg != 0) { |
3541 | 1 | S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) |
3542 | 1 | << FirstArgExpr->getSourceRange(); |
3543 | 1 | return; |
3544 | 1 | } |
3545 | | // if 0 it disables parameter checking (to use with e.g. va_list) |
3546 | 37.2k | } else if (FirstArg != 0 && FirstArg != NumArgs18.9k ) { |
3547 | 4 | S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) |
3548 | 4 | << AL << 3 << FirstArgExpr->getSourceRange(); |
3549 | 4 | return; |
3550 | 4 | } |
3551 | | |
3552 | 37.4k | FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg); |
3553 | 37.4k | if (NewAttr) |
3554 | 37.4k | D->addAttr(NewAttr); |
3555 | 37.4k | } |
3556 | | |
3557 | | /// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes. |
3558 | 142 | static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3559 | | // The index that identifies the callback callee is mandatory. |
3560 | 142 | if (AL.getNumArgs() == 0) { |
3561 | 2 | S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee) |
3562 | 2 | << AL.getRange(); |
3563 | 2 | return; |
3564 | 2 | } |
3565 | | |
3566 | 140 | bool HasImplicitThisParam = isInstanceMethod(D); |
3567 | 140 | int32_t NumArgs = getFunctionOrMethodNumParams(D); |
3568 | | |
3569 | 140 | FunctionDecl *FD = D->getAsFunction(); |
3570 | 140 | assert(FD && "Expected a function declaration!"); |
3571 | | |
3572 | 140 | llvm::StringMap<int> NameIdxMapping; |
3573 | 140 | NameIdxMapping["__"] = -1; |
3574 | | |
3575 | 140 | NameIdxMapping["this"] = 0; |
3576 | | |
3577 | 140 | int Idx = 1; |
3578 | 140 | for (const ParmVarDecl *PVD : FD->parameters()) |
3579 | 248 | NameIdxMapping[PVD->getName()] = Idx++; |
3580 | | |
3581 | 140 | auto UnknownName = NameIdxMapping.end(); |
3582 | | |
3583 | 140 | SmallVector<int, 8> EncodingIndices; |
3584 | 437 | for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I297 ) { |
3585 | 317 | SourceRange SR; |
3586 | 317 | int32_t ArgIdx; |
3587 | | |
3588 | 317 | if (AL.isArgIdent(I)) { |
3589 | 127 | IdentifierLoc *IdLoc = AL.getArgAsIdent(I); |
3590 | 127 | auto It = NameIdxMapping.find(IdLoc->Ident->getName()); |
3591 | 127 | if (It == UnknownName) { |
3592 | 4 | S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown) |
3593 | 4 | << IdLoc->Ident << IdLoc->Loc; |
3594 | 4 | return; |
3595 | 4 | } |
3596 | | |
3597 | 123 | SR = SourceRange(IdLoc->Loc); |
3598 | 123 | ArgIdx = It->second; |
3599 | 190 | } else if (AL.isArgExpr(I)) { |
3600 | 190 | Expr *IdxExpr = AL.getArgAsExpr(I); |
3601 | | |
3602 | | // If the expression is not parseable as an int32_t we have a problem. |
3603 | 190 | if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1, |
3604 | 0 | false)) { |
3605 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) |
3606 | 0 | << AL << (I + 1) << IdxExpr->getSourceRange(); |
3607 | 0 | return; |
3608 | 0 | } |
3609 | | |
3610 | | // Check oob, excluding the special values, 0 and -1. |
3611 | 190 | if (ArgIdx < -1 || ArgIdx > NumArgs186 ) { |
3612 | 10 | S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) |
3613 | 10 | << AL << (I + 1) << IdxExpr->getSourceRange(); |
3614 | 10 | return; |
3615 | 10 | } |
3616 | | |
3617 | 180 | SR = IdxExpr->getSourceRange(); |
3618 | 0 | } else { |
3619 | 0 | llvm_unreachable("Unexpected ParsedAttr argument type!"); |
3620 | 0 | } |
3621 | | |
3622 | 303 | if (ArgIdx == 0 && !HasImplicitThisParam14 ) { |
3623 | 6 | S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available) |
3624 | 6 | << (I + 1) << SR; |
3625 | 6 | return; |
3626 | 6 | } |
3627 | | |
3628 | | // Adjust for the case we do not have an implicit "this" parameter. In this |
3629 | | // case we decrease all positive values by 1 to get LLVM argument indices. |
3630 | 297 | if (!HasImplicitThisParam && ArgIdx > 0152 ) |
3631 | 116 | ArgIdx -= 1; |
3632 | | |
3633 | 297 | EncodingIndices.push_back(ArgIdx); |
3634 | 297 | } |
3635 | | |
3636 | 120 | int CalleeIdx = EncodingIndices.front(); |
3637 | | // Check if the callee index is proper, thus not "this" and not "unknown". |
3638 | | // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam" |
3639 | | // is false and positive if "HasImplicitThisParam" is true. |
3640 | 120 | if (CalleeIdx < (int)HasImplicitThisParam) { |
3641 | 6 | S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee) |
3642 | 6 | << AL.getRange(); |
3643 | 6 | return; |
3644 | 6 | } |
3645 | | |
3646 | | // Get the callee type, note the index adjustment as the AST doesn't contain |
3647 | | // the this type (which the callee cannot reference anyway!). |
3648 | 114 | const Type *CalleeType = |
3649 | 114 | getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam) |
3650 | 114 | .getTypePtr(); |
3651 | 114 | if (!CalleeType || !CalleeType->isFunctionPointerType()) { |
3652 | 0 | S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type) |
3653 | 0 | << AL.getRange(); |
3654 | 0 | return; |
3655 | 0 | } |
3656 | | |
3657 | 114 | const Type *CalleeFnType = |
3658 | 114 | CalleeType->getPointeeType()->getUnqualifiedDesugaredType(); |
3659 | | |
3660 | | // TODO: Check the type of the callee arguments. |
3661 | | |
3662 | 114 | const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType); |
3663 | 114 | if (!CalleeFnProtoType) { |
3664 | 0 | S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type) |
3665 | 0 | << AL.getRange(); |
3666 | 0 | return; |
3667 | 0 | } |
3668 | | |
3669 | 114 | if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) { |
3670 | 12 | S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) |
3671 | 12 | << AL << (unsigned)(EncodingIndices.size() - 1); |
3672 | 12 | return; |
3673 | 12 | } |
3674 | | |
3675 | 102 | if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) { |
3676 | 28 | S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) |
3677 | 28 | << AL << (unsigned)(EncodingIndices.size() - 1); |
3678 | 28 | return; |
3679 | 28 | } |
3680 | | |
3681 | 74 | if (CalleeFnProtoType->isVariadic()) { |
3682 | 8 | S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange(); |
3683 | 8 | return; |
3684 | 8 | } |
3685 | | |
3686 | | // Do not allow multiple callback attributes. |
3687 | 66 | if (D->hasAttr<CallbackAttr>()) { |
3688 | 8 | S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange(); |
3689 | 8 | return; |
3690 | 8 | } |
3691 | | |
3692 | 58 | D->addAttr(::new (S.Context) CallbackAttr( |
3693 | 58 | S.Context, AL, EncodingIndices.data(), EncodingIndices.size())); |
3694 | 58 | } |
3695 | | |
3696 | 91 | static bool isFunctionLike(const Type &T) { |
3697 | | // Check for explicit function types. |
3698 | | // 'called_once' is only supported in Objective-C and it has |
3699 | | // function pointers and block pointers. |
3700 | 91 | return T.isFunctionPointerType() || T.isBlockPointerType()88 ; |
3701 | 91 | } |
3702 | | |
3703 | | /// Handle 'called_once' attribute. |
3704 | 91 | static void handleCalledOnceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3705 | | // 'called_once' only applies to parameters representing functions. |
3706 | 91 | QualType T = cast<ParmVarDecl>(D)->getType(); |
3707 | | |
3708 | 91 | if (!isFunctionLike(*T)) { |
3709 | 2 | S.Diag(AL.getLoc(), diag::err_called_once_attribute_wrong_type); |
3710 | 2 | return; |
3711 | 2 | } |
3712 | | |
3713 | 89 | D->addAttr(::new (S.Context) CalledOnceAttr(S.Context, AL)); |
3714 | 89 | } |
3715 | | |
3716 | 66 | static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3717 | | // Try to find the underlying union declaration. |
3718 | 66 | RecordDecl *RD = nullptr; |
3719 | 66 | const auto *TD = dyn_cast<TypedefNameDecl>(D); |
3720 | 66 | if (TD && TD->getUnderlyingType()->isUnionType()38 ) |
3721 | 38 | RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); |
3722 | 28 | else |
3723 | 28 | RD = dyn_cast<RecordDecl>(D); |
3724 | | |
3725 | 66 | if (!RD || !RD->isUnion()) { |
3726 | 0 | S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL |
3727 | 0 | << ExpectedUnion; |
3728 | 0 | return; |
3729 | 0 | } |
3730 | | |
3731 | 66 | if (!RD->isCompleteDefinition()) { |
3732 | 8 | if (!RD->isBeingDefined()) |
3733 | 0 | S.Diag(AL.getLoc(), |
3734 | 0 | diag::warn_transparent_union_attribute_not_definition); |
3735 | 8 | return; |
3736 | 8 | } |
3737 | | |
3738 | 58 | RecordDecl::field_iterator Field = RD->field_begin(), |
3739 | 58 | FieldEnd = RD->field_end(); |
3740 | 58 | if (Field == FieldEnd) { |
3741 | 1 | S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields); |
3742 | 1 | return; |
3743 | 1 | } |
3744 | | |
3745 | 57 | FieldDecl *FirstField = *Field; |
3746 | 57 | QualType FirstType = FirstField->getType(); |
3747 | 57 | if (FirstType->hasFloatingRepresentation() || FirstType->isVectorType()56 ) { |
3748 | 2 | S.Diag(FirstField->getLocation(), |
3749 | 2 | diag::warn_transparent_union_attribute_floating) |
3750 | 2 | << FirstType->isVectorType() << FirstType; |
3751 | 2 | return; |
3752 | 2 | } |
3753 | | |
3754 | 55 | if (FirstType->isIncompleteType()) |
3755 | 3 | return; |
3756 | 52 | uint64_t FirstSize = S.Context.getTypeSize(FirstType); |
3757 | 52 | uint64_t FirstAlign = S.Context.getTypeAlign(FirstType); |
3758 | 223 | for (; Field != FieldEnd; ++Field171 ) { |
3759 | 177 | QualType FieldType = Field->getType(); |
3760 | 177 | if (FieldType->isIncompleteType()) |
3761 | 1 | return; |
3762 | | // FIXME: this isn't fully correct; we also need to test whether the |
3763 | | // members of the union would all have the same calling convention as the |
3764 | | // first member of the union. Checking just the size and alignment isn't |
3765 | | // sufficient (consider structs passed on the stack instead of in registers |
3766 | | // as an example). |
3767 | 176 | if (S.Context.getTypeSize(FieldType) != FirstSize || |
3768 | 174 | S.Context.getTypeAlign(FieldType) > FirstAlign) { |
3769 | | // Warn if we drop the attribute. |
3770 | 5 | bool isSize = S.Context.getTypeSize(FieldType) != FirstSize; |
3771 | 2 | unsigned FieldBits = isSize ? S.Context.getTypeSize(FieldType) |
3772 | 3 | : S.Context.getTypeAlign(FieldType); |
3773 | 5 | S.Diag(Field->getLocation(), |
3774 | 5 | diag::warn_transparent_union_attribute_field_size_align) |
3775 | 5 | << isSize << *Field << FieldBits; |
3776 | 3 | unsigned FirstBits = isSize ? FirstSize2 : FirstAlign; |
3777 | 5 | S.Diag(FirstField->getLocation(), |
3778 | 5 | diag::note_transparent_union_first_field_size_align) |
3779 | 5 | << isSize << FirstBits; |
3780 | 5 | return; |
3781 | 5 | } |
3782 | 176 | } |
3783 | | |
3784 | 46 | RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL)); |
3785 | 46 | } |
3786 | | |
3787 | | void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, |
3788 | 355 | StringRef Str, MutableArrayRef<Expr *> Args) { |
3789 | 355 | auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI); |
3790 | 355 | llvm::SmallVector<PartialDiagnosticAt, 8> Notes; |
3791 | 421 | for (unsigned Idx = 0; Idx < Attr->args_size(); Idx++66 ) { |
3792 | 72 | Expr *&E = Attr->args_begin()[Idx]; |
3793 | 72 | assert(E && "error are handled before"); |
3794 | 72 | if (E->isValueDependent() || E->isTypeDependent()48 ) |
3795 | 24 | continue; |
3796 | | |
3797 | 48 | if (E->getType()->isArrayType()) |
3798 | 2 | E = ImpCastExprToType(E, Context.getPointerType(E->getType()), |
3799 | 2 | clang::CK_ArrayToPointerDecay) |
3800 | 2 | .get(); |
3801 | 48 | if (E->getType()->isFunctionType()) |
3802 | 2 | E = ImplicitCastExpr::Create(Context, |
3803 | 2 | Context.getPointerType(E->getType()), |
3804 | 2 | clang::CK_FunctionToPointerDecay, E, nullptr, |
3805 | 2 | VK_RValue, FPOptionsOverride()); |
3806 | 48 | if (E->isLValue()) |
3807 | 8 | E = ImplicitCastExpr::Create(Context, E->getType().getNonReferenceType(), |
3808 | 8 | clang::CK_LValueToRValue, E, nullptr, |
3809 | 8 | VK_RValue, FPOptionsOverride()); |
3810 | | |
3811 | 48 | Expr::EvalResult Eval; |
3812 | 48 | Notes.clear(); |
3813 | 48 | Eval.Diag = &Notes; |
3814 | | |
3815 | 48 | bool Result = |
3816 | 48 | E->EvaluateAsConstantExpr(Eval, Context); |
3817 | | |
3818 | | /// Result means the expression can be folded to a constant. |
3819 | | /// Note.empty() means the expression is a valid constant expression in the |
3820 | | /// current language mode. |
3821 | 48 | if (!Result || !Notes.empty()43 ) { |
3822 | 6 | Diag(E->getBeginLoc(), diag::err_attribute_argument_n_type) |
3823 | 6 | << CI << (Idx + 1) << AANT_ArgumentConstantExpr; |
3824 | 6 | for (auto &Note : Notes) |
3825 | 10 | Diag(Note.first, Note.second); |
3826 | 6 | return; |
3827 | 6 | } |
3828 | 42 | assert(Eval.Val.hasValue()); |
3829 | 42 | E = ConstantExpr::Create(Context, E, Eval.Val); |
3830 | 42 | } |
3831 | 349 | D->addAttr(Attr); |
3832 | 349 | } |
3833 | | |
3834 | 334 | static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3835 | | // Make sure that there is a string literal as the annotation's first |
3836 | | // argument. |
3837 | 334 | StringRef Str; |
3838 | 334 | if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) |
3839 | 2 | return; |
3840 | | |
3841 | 332 | llvm::SmallVector<Expr *, 4> Args; |
3842 | 332 | Args.reserve(AL.getNumArgs() - 1); |
3843 | 372 | for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++40 ) { |
3844 | 40 | assert(!AL.isArgIdent(Idx)); |
3845 | 40 | Args.push_back(AL.getArgAsExpr(Idx)); |
3846 | 40 | } |
3847 | | |
3848 | 332 | S.AddAnnotationAttr(D, AL, Str, Args); |
3849 | 332 | } |
3850 | | |
3851 | 272 | static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3852 | 272 | S.AddAlignValueAttr(D, AL, AL.getArgAsExpr(0)); |
3853 | 272 | } |
3854 | | |
3855 | 275 | void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) { |
3856 | 275 | AlignValueAttr TmpAttr(Context, CI, E); |
3857 | 275 | SourceLocation AttrLoc = CI.getLoc(); |
3858 | | |
3859 | 275 | QualType T; |
3860 | 275 | if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) |
3861 | 14 | T = TD->getUnderlyingType(); |
3862 | 261 | else if (const auto *VD = dyn_cast<ValueDecl>(D)) |
3863 | 261 | T = VD->getType(); |
3864 | 261 | else |
3865 | 0 | llvm_unreachable("Unknown decl type for align_value"); |
3866 | | |
3867 | 275 | if (!T->isDependentType() && !T->isAnyPointerType()272 && |
3868 | 5 | !T->isReferenceType() && !T->isMemberPointerType()1 ) { |
3869 | 1 | Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only) |
3870 | 1 | << &TmpAttr << T << D->getSourceRange(); |
3871 | 1 | return; |
3872 | 1 | } |
3873 | | |
3874 | 274 | if (!E->isValueDependent()) { |
3875 | 271 | llvm::APSInt Alignment; |
3876 | 271 | ExprResult ICE = VerifyIntegerConstantExpression( |
3877 | 271 | E, &Alignment, diag::err_align_value_attribute_argument_not_int); |
3878 | 271 | if (ICE.isInvalid()) |
3879 | 1 | return; |
3880 | | |
3881 | 270 | if (!Alignment.isPowerOf2()) { |
3882 | 3 | Diag(AttrLoc, diag::err_alignment_not_power_of_two) |
3883 | 3 | << E->getSourceRange(); |
3884 | 3 | return; |
3885 | 3 | } |
3886 | | |
3887 | 267 | D->addAttr(::new (Context) AlignValueAttr(Context, CI, ICE.get())); |
3888 | 267 | return; |
3889 | 267 | } |
3890 | | |
3891 | | // Save dependent expressions in the AST to be instantiated. |
3892 | 3 | D->addAttr(::new (Context) AlignValueAttr(Context, CI, E)); |
3893 | 3 | } |
3894 | | |
3895 | 33.3k | static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3896 | | // check the attribute arguments. |
3897 | 33.3k | if (AL.getNumArgs() > 1) { |
3898 | 0 | S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; |
3899 | 0 | return; |
3900 | 0 | } |
3901 | | |
3902 | 33.3k | if (AL.getNumArgs() == 0) { |
3903 | 45 | D->addAttr(::new (S.Context) AlignedAttr(S.Context, AL, true, nullptr)); |
3904 | 45 | return; |
3905 | 45 | } |
3906 | | |
3907 | 33.3k | Expr *E = AL.getArgAsExpr(0); |
3908 | 33.3k | if (AL.isPackExpansion() && !E->containsUnexpandedParameterPack()9 ) { |
3909 | 1 | S.Diag(AL.getEllipsisLoc(), |
3910 | 1 | diag::err_pack_expansion_without_parameter_packs); |
3911 | 1 | return; |
3912 | 1 | } |
3913 | | |
3914 | 33.3k | if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)33.3k ) |
3915 | 3 | return; |
3916 | | |
3917 | 33.3k | S.AddAlignedAttr(D, AL, E, AL.isPackExpansion()); |
3918 | 33.3k | } |
3919 | | |
3920 | | void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, |
3921 | 33.4k | bool IsPackExpansion) { |
3922 | 33.4k | AlignedAttr TmpAttr(Context, CI, true, E); |
3923 | 33.4k | SourceLocation AttrLoc = CI.getLoc(); |
3924 | | |
3925 | | // C++11 alignas(...) and C11 _Alignas(...) have additional requirements. |
3926 | 33.4k | if (TmpAttr.isAlignas()) { |
3927 | | // C++11 [dcl.align]p1: |
3928 | | // An alignment-specifier may be applied to a variable or to a class |
3929 | | // data member, but it shall not be applied to a bit-field, a function |
3930 | | // parameter, the formal parameter of a catch clause, or a variable |
3931 | | // declared with the register storage class specifier. An |
3932 | | // alignment-specifier may also be applied to the declaration of a class |
3933 | | // or enumeration type. |
3934 | | // C11 6.7.5/2: |
3935 | | // An alignment attribute shall not be specified in a declaration of |
3936 | | // a typedef, or a bit-field, or a function, or a parameter, or an |
3937 | | // object declared with the register storage-class specifier. |
3938 | 9.39k | int DiagKind = -1; |
3939 | 9.39k | if (isa<ParmVarDecl>(D)) { |
3940 | 3 | DiagKind = 0; |
3941 | 9.39k | } else if (const auto *VD = dyn_cast<VarDecl>(D)) { |
3942 | 1.27k | if (VD->getStorageClass() == SC_Register) |
3943 | 3 | DiagKind = 1; |
3944 | 1.27k | if (VD->isExceptionVariable()) |
3945 | 1 | DiagKind = 2; |
3946 | 8.11k | } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { |
3947 | 84 | if (FD->isBitField()) |
3948 | 3 | DiagKind = 3; |
3949 | 8.03k | } else if (!isa<TagDecl>(D)) { |
3950 | 7 | Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr |
3951 | 2 | << (TmpAttr.isC11() ? ExpectedVariableOrField |
3952 | 5 | : ExpectedVariableFieldOrTag); |
3953 | 7 | return; |
3954 | 7 | } |
3955 | 9.39k | if (DiagKind != -1) { |
3956 | 10 | Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) |
3957 | 10 | << &TmpAttr << DiagKind; |
3958 | 10 | return; |
3959 | 10 | } |
3960 | 33.4k | } |
3961 | | |
3962 | 33.4k | if (E->isValueDependent()) { |
3963 | | // We can't support a dependent alignment on a non-dependent type, |
3964 | | // because we have no way to model that a type is "alignment-dependent" |
3965 | | // but not dependent in any other way. |
3966 | 923 | if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { |
3967 | 2 | if (!TND->getUnderlyingType()->isDependentType()) { |
3968 | 2 | Diag(AttrLoc, diag::err_alignment_dependent_typedef_name) |
3969 | 2 | << E->getSourceRange(); |
3970 | 2 | return; |
3971 | 2 | } |
3972 | 921 | } |
3973 | | |
3974 | | // Save dependent expressions in the AST to be instantiated. |
3975 | 921 | AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, E); |
3976 | 921 | AA->setPackExpansion(IsPackExpansion); |
3977 | 921 | D->addAttr(AA); |
3978 | 921 | return; |
3979 | 921 | } |
3980 | | |
3981 | | // FIXME: Cache the number on the AL object? |
3982 | 32.5k | llvm::APSInt Alignment; |
3983 | 32.5k | ExprResult ICE = VerifyIntegerConstantExpression( |
3984 | 32.5k | E, &Alignment, diag::err_aligned_attribute_argument_not_int); |
3985 | 32.5k | if (ICE.isInvalid()) |
3986 | 3 | return; |
3987 | | |
3988 | 32.5k | uint64_t AlignVal = Alignment.getZExtValue(); |
3989 | | |
3990 | | // C++11 [dcl.align]p2: |
3991 | | // -- if the constant expression evaluates to zero, the alignment |
3992 | | // specifier shall have no effect |
3993 | | // C11 6.7.5p6: |
3994 | | // An alignment specification of zero has no effect. |
3995 | 32.5k | if (!(TmpAttr.isAlignas() && !Alignment8.46k )) { |
3996 | 32.5k | if (!llvm::isPowerOf2_64(AlignVal)) { |
3997 | 6 | Diag(AttrLoc, diag::err_alignment_not_power_of_two) |
3998 | 6 | << E->getSourceRange(); |
3999 | 6 | return; |
4000 | 6 | } |
4001 | 32.5k | } |
4002 | | |
4003 | 32.5k | unsigned MaximumAlignment = Sema::MaximumAlignment; |
4004 | 32.5k | if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF()) |
4005 | 841 | MaximumAlignment = std::min(MaximumAlignment, 8192u); |
4006 | 32.5k | if (AlignVal > MaximumAlignment) { |
4007 | 15 | Diag(AttrLoc, diag::err_attribute_aligned_too_great) |
4008 | 15 | << MaximumAlignment << E->getSourceRange(); |
4009 | 15 | return; |
4010 | 15 | } |
4011 | | |
4012 | 32.5k | if (Context.getTargetInfo().isTLSSupported()) { |
4013 | 28.9k | unsigned MaxTLSAlign = |
4014 | 28.9k | Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) |
4015 | 28.9k | .getQuantity(); |
4016 | 28.9k | const auto *VD = dyn_cast<VarDecl>(D); |
4017 | 28.9k | if (MaxTLSAlign && AlignVal > MaxTLSAlign888 && VD7 && |
4018 | 2 | VD->getTLSKind() != VarDecl::TLS_None) { |
4019 | 2 | Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) |
4020 | 2 | << (unsigned)AlignVal << VD << MaxTLSAlign; |
4021 | 2 | return; |
4022 | 2 | } |
4023 | 32.5k | } |
4024 | | |
4025 | 32.5k | AlignedAttr *AA = ::new (Context) AlignedAtt
|