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