 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
74.0% |
743 / 1004 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
93.6% |
940 / 1004 |
| |
|
Line Coverage: |
82.8% |
856 / 1034 |
| |
 |
|
 |
1 : //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file implements decl-related attribute processing.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "Sema.h"
15 : #include "TargetAttributesSema.h"
16 : #include "clang/AST/ASTContext.h"
17 : #include "clang/AST/DeclObjC.h"
18 : #include "clang/AST/Expr.h"
19 : #include "clang/Basic/TargetInfo.h"
20 : #include "clang/Parse/DeclSpec.h"
21 : #include "llvm/ADT/StringExtras.h"
22 : using namespace clang;
23 :
24 : //===----------------------------------------------------------------------===//
25 : // Helper functions
26 : //===----------------------------------------------------------------------===//
27 :
28 : static const FunctionType *getFunctionType(const Decl *d,
29 3536: bool blocksToo = true) {
30 3536: QualType Ty;
3483: branch 1 taken
53: branch 2 taken
31 3536: if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
32 3483: Ty = decl->getType();
0: branch 1 not taken
53: branch 2 taken
33 53: else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
34 0: Ty = decl->getType();
5: branch 1 taken
48: branch 2 taken
35 53: else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
36 5: Ty = decl->getUnderlyingType();
37 : else
38 48: return 0;
39 :
29: branch 2 taken
3459: branch 3 taken
40 3488: if (Ty->isFunctionPointerType())
41 29: Ty = Ty->getAs<PointerType>()->getPointeeType();
1699: branch 0 taken
1760: branch 1 taken
7: branch 4 taken
1692: branch 5 taken
7: branch 6 taken
3452: branch 7 taken
42 3459: else if (blocksToo && Ty->isBlockPointerType())
43 7: Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
44 :
45 3488: return Ty->getAs<FunctionType>();
46 : }
47 :
48 : // FIXME: We should provide an abstraction around a method or function
49 : // to provide the following bits of information.
50 :
51 : /// isFunction - Return true if the given decl has function
52 : /// type (function or function-typed variable).
53 1785: static bool isFunction(const Decl *d) {
54 1785: return getFunctionType(d, false) != NULL;
55 : }
56 :
57 : /// isFunctionOrMethod - Return true if the given decl has function
58 : /// type (function or function-typed variable) or an Objective-C
59 : /// method.
60 1785: static bool isFunctionOrMethod(const Decl *d) {
22: branch 1 taken
1763: branch 2 taken
9: branch 4 taken
13: branch 5 taken
61 1785: return isFunction(d)|| isa<ObjCMethodDecl>(d);
62 : }
63 :
64 : /// isFunctionOrMethodOrBlock - Return true if the given decl has function
65 : /// type (function or function-typed variable) or an Objective-C
66 : /// method or a block.
67 75: static bool isFunctionOrMethodOrBlock(const Decl *d) {
71: branch 1 taken
4: branch 2 taken
68 75: if (isFunctionOrMethod(d))
69 71: return true;
70 : // check for block is more involved.
2: branch 1 taken
2: branch 2 taken
71 4: if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
72 2: QualType Ty = V->getType();
73 2: return Ty->isBlockPointerType();
74 : }
75 2: return isa<BlockDecl>(d);
76 : }
77 :
78 : /// hasFunctionProto - Return true if the given decl has a argument
79 : /// information. This decl should have already passed
80 : /// isFunctionOrMethod or isFunctionOrMethodOrBlock.
81 495: static bool hasFunctionProto(const Decl *d) {
487: branch 1 taken
8: branch 2 taken
82 495: if (const FunctionType *FnTy = getFunctionType(d))
83 487: return isa<FunctionProtoType>(FnTy);
84 : else {
2: branch 1 taken
6: branch 2 taken
0: branch 4 not taken
2: branch 5 taken
85 8: assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d));
86 8: return true;
87 : }
88 : }
89 :
90 : /// getFunctionOrMethodNumArgs - Return number of function or method
91 : /// arguments. It is an error to call this on a K&R function (use
92 : /// hasFunctionProto first).
93 506: static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
498: branch 1 taken
8: branch 2 taken
94 506: if (const FunctionType *FnTy = getFunctionType(d))
95 498: return cast<FunctionProtoType>(FnTy)->getNumArgs();
2: branch 1 taken
6: branch 2 taken
96 8: if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
97 2: return BD->getNumParams();
98 6: return cast<ObjCMethodDecl>(d)->param_size();
99 : }
100 :
101 682: static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) {
674: branch 1 taken
8: branch 2 taken
102 682: if (const FunctionType *FnTy = getFunctionType(d))
103 674: return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
2: branch 1 taken
6: branch 2 taken
104 8: if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
105 2: return BD->getParamDecl(Idx)->getType();
106 :
107 6: return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
108 : }
109 :
110 10: static QualType getFunctionOrMethodResultType(const Decl *d) {
10: branch 1 taken
0: branch 2 not taken
111 10: if (const FunctionType *FnTy = getFunctionType(d))
112 10: return cast<FunctionProtoType>(FnTy)->getResultType();
113 0: return cast<ObjCMethodDecl>(d)->getResultType();
114 : }
115 :
116 42: static bool isFunctionOrMethodVariadic(const Decl *d) {
36: branch 1 taken
6: branch 2 taken
117 42: if (const FunctionType *FnTy = getFunctionType(d)) {
118 36: const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
119 36: return proto->isVariadic();
1: branch 1 taken
5: branch 2 taken
120 6: } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
121 1: return BD->IsVariadic();
122 : else {
123 5: return cast<ObjCMethodDecl>(d)->isVariadic();
124 : }
125 : }
126 :
127 42: static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
128 42: const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
7: branch 0 taken
35: branch 1 taken
129 42: if (!PT)
130 7: return false;
131 :
132 35: const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>();
0: branch 0 not taken
35: branch 1 taken
133 35: if (!ClsT)
134 0: return false;
135 :
136 35: IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
137 :
138 : // FIXME: Should we walk the chain of classes?
139 : return ClsName == &Ctx.Idents.get("NSString") ||
0: branch 2 not taken
35: branch 3 taken
0: branch 6 not taken
0: branch 7 not taken
140 35: ClsName == &Ctx.Idents.get("NSMutableString");
141 : }
142 :
143 8: static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
144 8: const PointerType *PT = T->getAs<PointerType>();
2: branch 0 taken
6: branch 1 taken
145 8: if (!PT)
146 2: return false;
147 :
148 6: const RecordType *RT = PT->getPointeeType()->getAs<RecordType>();
5: branch 0 taken
1: branch 1 taken
149 6: if (!RT)
150 5: return false;
151 :
152 1: const RecordDecl *RD = RT->getDecl();
0: branch 1 not taken
1: branch 2 taken
153 1: if (RD->getTagKind() != TagDecl::TK_struct)
154 0: return false;
155 :
156 1: return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
157 : }
158 :
159 : //===----------------------------------------------------------------------===//
160 : // Attribute Implementations
161 : //===----------------------------------------------------------------------===//
162 :
163 : // FIXME: All this manual attribute parsing code is gross. At the
164 : // least add some helper functions to check most argument patterns (#
165 : // and types of args).
166 :
167 : static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
168 65: const AttributeList &Attr, Sema &S) {
169 65: TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
0: branch 0 not taken
65: branch 1 taken
170 65: if (tDecl == 0) {
171 0: S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
172 0: return;
173 : }
174 :
175 65: QualType curType = tDecl->getUnderlyingType();
176 :
177 : Expr *sizeExpr;
178 :
179 : // Special case where the argument is a template id.
9: branch 1 taken
56: branch 2 taken
180 65: if (Attr.getParameterName()) {
181 9: CXXScopeSpec SS;
182 9: UnqualifiedId id;
183 9: id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
184 9: sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>();
185 : } else {
186 : // check the attribute arguments.
0: branch 1 not taken
56: branch 2 taken
187 56: if (Attr.getNumArgs() != 1) {
188 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
189 0: return;
190 : }
191 56: sizeExpr = static_cast<Expr *>(Attr.getArg(0));
192 : }
193 :
194 : // Instantiate/Install the vector type, and let Sema build the type for us.
195 : // This will run the reguired checks.
196 65: QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
64: branch 1 taken
1: branch 2 taken
197 65: if (!T.isNull()) {
198 : // FIXME: preserve the old source info.
199 64: tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T));
200 :
201 : // Remember this typedef decl, we will need it later for diagnostics.
202 64: S.ExtVectorDecls.push_back(tDecl);
203 : }
204 : }
205 :
206 26: static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
207 : // check the attribute arguments.
0: branch 1 not taken
26: branch 2 taken
208 26: if (Attr.getNumArgs() > 0) {
209 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
210 0: return;
211 : }
212 :
17: branch 1 taken
9: branch 2 taken
213 26: if (TagDecl *TD = dyn_cast<TagDecl>(d))
17: branch 1 taken
0: branch 2 not taken
214 17: TD->addAttr(::new (S.Context) PackedAttr);
9: branch 1 taken
0: branch 2 not taken
215 9: else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) {
216 : // If the alignment is less than or equal to 8 bits, the packed attribute
217 : // has no effect.
8: branch 3 taken
1: branch 4 taken
0: branch 7 not taken
8: branch 8 taken
0: branch 9 not taken
9: branch 10 taken
218 9: if (!FD->getType()->isIncompleteType() &&
219 : S.Context.getTypeAlign(FD->getType()) <= 8)
220 : S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
221 0: << Attr.getName() << FD->getType();
222 : else
9: branch 1 taken
0: branch 2 not taken
223 9: FD->addAttr(::new (S.Context) PackedAttr);
224 : } else
225 0: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
226 : }
227 :
228 1: static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
229 : // check the attribute arguments.
0: branch 1 not taken
1: branch 2 taken
230 1: if (Attr.getNumArgs() > 0) {
231 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
232 0: return;
233 : }
234 :
235 : // The IBOutlet attribute only applies to instance variables of Objective-C
236 : // classes.
0: branch 1 not taken
1: branch 2 taken
0: branch 4 not taken
0: branch 5 not taken
1: branch 6 taken
0: branch 7 not taken
237 1: if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))
1: branch 1 taken
0: branch 2 not taken
238 1: d->addAttr(::new (S.Context) IBOutletAttr());
239 : else
240 0: S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet);
241 : }
242 :
243 409: static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
244 : // GCC ignores the nonnull attribute on K&R style function prototypes, so we
245 : // ignore it as well
409: branch 1 taken
0: branch 2 not taken
0: branch 4 not taken
409: branch 5 taken
0: branch 6 not taken
409: branch 7 taken
246 409: if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
247 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
248 0: << Attr.getName() << 0 /*function*/;
249 0: return;
250 : }
251 :
252 409: unsigned NumArgs = getFunctionOrMethodNumArgs(d);
253 :
254 : // The nonnull attribute only applies to pointers.
255 409: llvm::SmallVector<unsigned, 10> NonNullArgs;
256 :
582: branch 2 taken
1: branch 3 taken
0: branch 4 not taken
583: branch 7 taken
408: branch 8 taken
257 1983: for (AttributeList::arg_iterator I=Attr.arg_begin(),
258 409: E=Attr.arg_end(); I!=E; ++I) {
259 :
260 :
261 : // The argument must be an integer constant expression.
262 583: Expr *Ex = static_cast<Expr *>(*I);
263 583: llvm::APSInt ArgNum(32);
0: branch 1 not taken
583: branch 2 taken
264 583: if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
265 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
266 0: << "nonnull" << Ex->getSourceRange();
267 2: return;
268 : }
269 :
270 583: unsigned x = (unsigned) ArgNum.getZExtValue();
271 :
582: branch 0 taken
1: branch 1 taken
0: branch 2 not taken
582: branch 3 taken
272 583: if (x < 1 || x > NumArgs) {
273 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
274 1: << "nonnull" << I.getArgNum() << Ex->getSourceRange();
275 : return;
276 : }
277 :
278 582: --x;
279 :
280 : // Is the function argument a pointer type?
281 582: QualType T = getFunctionOrMethodArgType(d, x);
4: branch 2 taken
578: branch 3 taken
0: branch 6 not taken
4: branch 7 taken
0: branch 8 not taken
582: branch 9 taken
282 582: if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
283 : // FIXME: Should also highlight argument in decl.
284 : S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only)
285 0: << "nonnull" << Ex->getSourceRange();
286 0: continue;
287 : }
288 :
289 582: NonNullArgs.push_back(x);
290 : }
291 :
292 : // If no arguments were specified to __attribute__((nonnull)) then all pointer
293 : // arguments have a nonnull attribute.
11: branch 1 taken
397: branch 2 taken
294 408: if (NonNullArgs.empty()) {
17: branch 1 taken
11: branch 2 taken
295 28: for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
296 17: QualType T = getFunctionOrMethodArgType(d, I);
8: branch 2 taken
9: branch 3 taken
2: branch 6 taken
6: branch 7 taken
11: branch 8 taken
6: branch 9 taken
297 17: if (T->isAnyPointerType() || T->isBlockPointerType())
298 11: NonNullArgs.push_back(I);
299 : }
300 :
1: branch 1 taken
10: branch 2 taken
301 11: if (NonNullArgs.empty()) {
302 1: S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
303 : return;
304 : }
305 : }
306 :
307 407: unsigned* start = &NonNullArgs[0];
308 407: unsigned size = NonNullArgs.size();
309 407: std::sort(start, start + size);
407: branch 1 taken
0: branch 2 not taken
407: branch 6 taken
2: branch 7 taken
310 407: d->addAttr(::new (S.Context) NonNullAttr(start, size));
311 : }
312 :
313 11: static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
314 : // check the attribute arguments.
0: branch 1 not taken
11: branch 2 taken
315 11: if (Attr.getNumArgs() != 1) {
316 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
317 0: return;
318 : }
319 :
320 11: Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
321 11: Arg = Arg->IgnoreParenCasts();
322 11: StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
323 :
11: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
11: branch 4 taken
0: branch 5 not taken
11: branch 6 taken
324 11: if (Str == 0 || Str->isWide()) {
325 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
326 0: << "alias" << 1;
327 0: return;
328 : }
329 :
330 : // FIXME: check if target symbol exists in current file
331 :
11: branch 2 taken
0: branch 3 not taken
332 11: d->addAttr(::new (S.Context) AliasAttr(Str->getString()));
333 : }
334 :
335 : static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
336 1279: Sema &S) {
337 : // check the attribute arguments.
0: branch 1 not taken
1279: branch 2 taken
338 1279: if (Attr.getNumArgs() != 0) {
339 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
340 0: return;
341 : }
342 :
0: branch 1 not taken
1279: branch 2 taken
343 1279: if (!isa<FunctionDecl>(d)) {
344 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
345 0: << Attr.getName() << 0 /*function*/;
346 0: return;
347 : }
348 :
1279: branch 1 taken
0: branch 2 not taken
349 1279: d->addAttr(::new (S.Context) AlwaysInlineAttr());
350 : }
351 :
352 46: static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
353 : // check the attribute arguments.
0: branch 1 not taken
46: branch 2 taken
354 46: if (Attr.getNumArgs() != 0) {
355 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
356 0: return;
357 : }
358 :
35: branch 1 taken
11: branch 2 taken
359 46: if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
360 35: QualType RetTy = FD->getResultType();
5: branch 2 taken
30: branch 3 taken
1: branch 6 taken
4: branch 7 taken
31: branch 8 taken
4: branch 9 taken
361 35: if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
31: branch 1 taken
0: branch 2 not taken
362 31: d->addAttr(::new (S.Context) MallocAttr());
363 31: return;
364 : }
365 : }
366 :
367 15: S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
368 : }
369 :
370 : static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
371 14: Sema &S) {
372 : // check the attribute arguments.
0: branch 1 not taken
14: branch 2 taken
373 14: if (Attr.getNumArgs() != 0) {
374 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
375 0: return false;
376 : }
377 :
3: branch 1 taken
11: branch 2 taken
0: branch 4 not taken
3: branch 5 taken
0: branch 6 not taken
14: branch 7 taken
378 14: if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
379 0: ValueDecl *VD = dyn_cast<ValueDecl>(d);
0: branch 0 not taken
0: branch 1 not taken
0: branch 5 not taken
0: branch 6 not taken
0: branch 10 not taken
0: branch 11 not taken
0: branch 12 not taken
0: branch 13 not taken
380 0: if (VD == 0 || (!VD->getType()->isBlockPointerType()
381 : && !VD->getType()->isFunctionPointerType())) {
382 : S.Diag(Attr.getLoc(),
383 : Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
384 : : diag::warn_attribute_wrong_decl_type)
0: branch 2 not taken
0: branch 3 not taken
385 0: << Attr.getName() << 0 /*function*/;
386 0: return false;
387 : }
388 : }
389 :
390 14: return true;
391 : }
392 :
393 105: static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
394 : // Don't apply as a decl attribute to ValueDecl.
395 : // FIXME: probably ought to diagnose this.
99: branch 1 taken
6: branch 2 taken
396 105: if (isa<ValueDecl>(d))
397 99: return;
398 :
6: branch 1 taken
0: branch 2 not taken
399 6: if (HandleCommonNoReturnAttr(d, Attr, S))
6: branch 1 taken
0: branch 2 not taken
400 6: d->addAttr(::new (S.Context) NoReturnAttr());
401 : }
402 :
403 : static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
404 8: Sema &S) {
8: branch 1 taken
0: branch 2 not taken
405 8: if (HandleCommonNoReturnAttr(d, Attr, S))
8: branch 1 taken
0: branch 2 not taken
406 8: d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
407 8: }
408 :
409 0: static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
0: branch 2 not taken
0: branch 4 not taken
0: branch 5 not taken
0: branch 6 not taken
0: branch 7 not taken
410 0: if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
411 : S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
412 0: << Attr.getName() << 8 /*function, method, or parameter*/;
413 0: return;
414 : }
415 : // FIXME: Actually store the attribute on the declaration
416 : }
417 :
418 24: static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
419 : // check the attribute arguments.
1: branch 1 taken
23: branch 2 taken
420 24: if (Attr.getNumArgs() != 0) {
421 1: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
422 1: return;
423 : }
424 :
5: branch 1 taken
18: branch 2 taken
0: branch 4 not taken
5: branch 5 taken
0: branch 6 not taken
23: branch 7 taken
425 23: if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
426 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
427 0: << Attr.getName() << 2 /*variable and function*/;
428 0: return;
429 : }
430 :
23: branch 1 taken
0: branch 2 not taken
431 23: d->addAttr(::new (S.Context) UnusedAttr());
432 : }
433 :
434 16: static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
435 : // check the attribute arguments.
0: branch 1 not taken
16: branch 2 taken
436 16: if (Attr.getNumArgs() != 0) {
437 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
438 0: return;
439 : }
440 :
13: branch 1 taken
3: branch 2 taken
441 16: if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
12: branch 1 taken
1: branch 2 taken
2: branch 4 taken
10: branch 5 taken
3: branch 6 taken
10: branch 7 taken
442 13: if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
443 3: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
444 3: return;
445 : }
1: branch 1 taken
2: branch 2 taken
446 3: } else if (!isFunctionOrMethod(d)) {
447 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
448 1: << Attr.getName() << 2 /*variable and function*/;
449 1: return;
450 : }
451 :
12: branch 1 taken
0: branch 2 not taken
452 12: d->addAttr(::new (S.Context) UsedAttr());
453 : }
454 :
455 8: static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
456 : // check the attribute arguments.
3: branch 1 taken
5: branch 2 taken
1: branch 4 taken
2: branch 5 taken
1: branch 6 taken
7: branch 7 taken
457 8: if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
458 : S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
459 1: << "0 or 1";
460 1: return;
461 : }
462 :
463 7: int priority = 65535; // FIXME: Do not hardcode such constants.
2: branch 1 taken
5: branch 2 taken
464 7: if (Attr.getNumArgs() > 0) {
465 2: Expr *E = static_cast<Expr *>(Attr.getArg(0));
466 2: llvm::APSInt Idx(32);
1: branch 1 taken
1: branch 2 taken
467 2: if (!E->isIntegerConstantExpr(Idx, S.Context)) {
468 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
469 1: << "constructor" << 1 << E->getSourceRange();
470 1: return;
471 : }
1: branch 2 taken
1: branch 3 taken
472 1: priority = Idx.getZExtValue();
473 : }
474 :
1: branch 1 taken
5: branch 2 taken
475 6: if (!isa<FunctionDecl>(d)) {
476 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
477 1: << Attr.getName() << 0 /*function*/;
478 1: return;
479 : }
480 :
5: branch 1 taken
0: branch 2 not taken
481 5: d->addAttr(::new (S.Context) ConstructorAttr(priority));
482 : }
483 :
484 7: static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
485 : // check the attribute arguments.
3: branch 1 taken
4: branch 2 taken
1: branch 4 taken
2: branch 5 taken
1: branch 6 taken
6: branch 7 taken
486 7: if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
487 : S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
488 1: << "0 or 1";
489 1: return;
490 : }
491 :
492 6: int priority = 65535; // FIXME: Do not hardcode such constants.
2: branch 1 taken
4: branch 2 taken
493 6: if (Attr.getNumArgs() > 0) {
494 2: Expr *E = static_cast<Expr *>(Attr.getArg(0));
495 2: llvm::APSInt Idx(32);
1: branch 1 taken
1: branch 2 taken
496 2: if (!E->isIntegerConstantExpr(Idx, S.Context)) {
497 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
498 1: << "destructor" << 1 << E->getSourceRange();
499 1: return;
500 : }
1: branch 2 taken
1: branch 3 taken
501 1: priority = Idx.getZExtValue();
502 : }
503 :
1: branch 1 taken
4: branch 2 taken
504 5: if (!isa<FunctionDecl>(d)) {
505 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
506 1: << Attr.getName() << 0 /*function*/;
507 1: return;
508 : }
509 :
4: branch 1 taken
0: branch 2 not taken
510 4: d->addAttr(::new (S.Context) DestructorAttr(priority));
511 : }
512 :
513 46: static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
514 : // check the attribute arguments.
0: branch 1 not taken
46: branch 2 taken
515 46: if (Attr.getNumArgs() != 0) {
516 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
517 0: return;
518 : }
519 :
46: branch 1 taken
0: branch 2 not taken
520 46: d->addAttr(::new (S.Context) DeprecatedAttr());
521 : }
522 :
523 9: static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
524 : // check the attribute arguments.
0: branch 1 not taken
9: branch 2 taken
525 9: if (Attr.getNumArgs() != 0) {
526 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
527 0: return;
528 : }
529 :
9: branch 1 taken
0: branch 2 not taken
530 9: d->addAttr(::new (S.Context) UnavailableAttr());
531 : }
532 :
533 14: static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
534 : // check the attribute arguments.
0: branch 1 not taken
14: branch 2 taken
535 14: if (Attr.getNumArgs() != 1) {
536 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
537 0: return;
538 : }
539 :
540 14: Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
541 14: Arg = Arg->IgnoreParenCasts();
542 14: StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
543 :
14: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
14: branch 4 taken
0: branch 5 not taken
14: branch 6 taken
544 14: if (Str == 0 || Str->isWide()) {
545 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
546 0: << "visibility" << 1;
547 0: return;
548 : }
549 :
550 14: llvm::StringRef TypeStr = Str->getString();
551 : VisibilityAttr::VisibilityTypes type;
552 :
4: branch 2 taken
10: branch 3 taken
553 14: if (TypeStr == "default")
554 4: type = VisibilityAttr::DefaultVisibility;
9: branch 2 taken
1: branch 3 taken
555 10: else if (TypeStr == "hidden")
556 9: type = VisibilityAttr::HiddenVisibility;
0: branch 2 not taken
1: branch 3 taken
557 1: else if (TypeStr == "internal")
558 0: type = VisibilityAttr::HiddenVisibility; // FIXME
1: branch 2 taken
0: branch 3 not taken
559 1: else if (TypeStr == "protected")
560 1: type = VisibilityAttr::ProtectedVisibility;
561 : else {
562 0: S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
563 0: return;
564 : }
565 :
14: branch 1 taken
0: branch 2 not taken
566 14: d->addAttr(::new (S.Context) VisibilityAttr(type));
567 : }
568 :
569 : static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
570 7: Sema &S) {
0: branch 1 not taken
7: branch 2 taken
571 7: if (Attr.getNumArgs() != 0) {
572 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
573 0: return;
574 : }
575 :
576 7: ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
2: branch 0 taken
5: branch 1 taken
577 7: if (OCI == 0) {
578 2: S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
579 2: return;
580 : }
581 :
5: branch 1 taken
0: branch 2 not taken
582 5: D->addAttr(::new (S.Context) ObjCExceptionAttr());
583 : }
584 :
585 4: static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
4: branch 2 taken
586 4: if (Attr.getNumArgs() != 0) {
587 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
588 0: return;
589 : }
4: branch 1 taken
0: branch 2 not taken
590 4: if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
591 4: QualType T = TD->getUnderlyingType();
3: branch 2 taken
1: branch 3 taken
1: branch 9 taken
2: branch 10 taken
2: branch 11 taken
2: branch 12 taken
592 4: if (!T->isPointerType() ||
593 : !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
594 2: S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
595 2: return;
596 : }
597 : }
2: branch 1 taken
0: branch 2 not taken
598 2: D->addAttr(::new (S.Context) ObjCNSObjectAttr());
599 : }
600 :
601 : static void
602 35: HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
35: branch 2 taken
603 35: if (Attr.getNumArgs() != 0) {
604 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
605 0: return;
606 : }
607 :
1: branch 1 taken
34: branch 2 taken
608 35: if (!isa<FunctionDecl>(D)) {
609 1: S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
610 1: return;
611 : }
612 :
34: branch 1 taken
0: branch 2 not taken
613 34: D->addAttr(::new (S.Context) OverloadableAttr());
614 : }
615 :
616 112: static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
112: branch 2 taken
617 112: if (!Attr.getParameterName()) {
618 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
619 0: << "blocks" << 1;
620 0: return;
621 : }
622 :
0: branch 1 not taken
112: branch 2 taken
623 112: if (Attr.getNumArgs() != 0) {
624 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
625 0: return;
626 : }
627 :
628 : BlocksAttr::BlocksAttrTypes type;
112: branch 2 taken
0: branch 3 not taken
629 112: if (Attr.getParameterName()->isStr("byref"))
630 112: type = BlocksAttr::ByRef;
631 : else {
632 : S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
633 0: << "blocks" << Attr.getParameterName();
634 0: return;
635 : }
636 :
112: branch 1 taken
0: branch 2 not taken
637 224: d->addAttr(::new (S.Context) BlocksAttr(type));
638 : }
639 :
640 40: static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
641 : // check the attribute arguments.
2: branch 1 taken
38: branch 2 taken
642 40: if (Attr.getNumArgs() > 2) {
643 : S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
644 2: << "0, 1 or 2";
645 2: return;
646 : }
647 :
648 38: int sentinel = 0;
22: branch 1 taken
16: branch 2 taken
649 38: if (Attr.getNumArgs() > 0) {
650 22: Expr *E = static_cast<Expr *>(Attr.getArg(0));
651 22: llvm::APSInt Idx(32);
2: branch 1 taken
20: branch 2 taken
652 22: if (!E->isIntegerConstantExpr(Idx, S.Context)) {
653 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
654 2: << "sentinel" << 1 << E->getSourceRange();
655 4: return;
656 : }
657 20: sentinel = Idx.getZExtValue();
658 :
2: branch 0 taken
18: branch 1 taken
659 20: if (sentinel < 0) {
660 : S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
661 2: << E->getSourceRange();
662 : return;
18: branch 1 taken
4: branch 2 taken
663 22: }
664 : }
665 :
666 34: int nullPos = 0;
5: branch 1 taken
29: branch 2 taken
667 34: if (Attr.getNumArgs() > 1) {
668 5: Expr *E = static_cast<Expr *>(Attr.getArg(1));
669 5: llvm::APSInt Idx(32);
0: branch 1 not taken
5: branch 2 taken
670 5: if (!E->isIntegerConstantExpr(Idx, S.Context)) {
671 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
672 0: << "sentinel" << 2 << E->getSourceRange();
673 1: return;
674 : }
675 5: nullPos = Idx.getZExtValue();
676 :
4: branch 0 taken
1: branch 1 taken
0: branch 2 not taken
4: branch 3 taken
677 5: if (nullPos > 1 || nullPos < 0) {
678 : // FIXME: This error message could be improved, it would be nice
679 : // to say what the bounds actually are.
680 : S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one)
681 1: << E->getSourceRange();
682 : return;
4: branch 1 taken
1: branch 2 taken
683 5: }
684 : }
685 :
13: branch 1 taken
20: branch 2 taken
686 33: if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
687 13: const FunctionType *FT = FD->getType()->getAs<FunctionType>();
0: branch 0 not taken
13: branch 1 taken
688 13: assert(FT && "FunctionDecl has non-function type?");
689 :
1: branch 1 taken
12: branch 2 taken
690 13: if (isa<FunctionNoProtoType>(FT)) {
691 1: S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments);
692 1: return;
693 : }
694 :
1: branch 2 taken
11: branch 3 taken
695 12: if (!cast<FunctionProtoType>(FT)->isVariadic()) {
696 1: S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
697 1: return;
698 : }
7: branch 1 taken
13: branch 2 taken
699 20: } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
1: branch 1 taken
6: branch 2 taken
700 7: if (!MD->isVariadic()) {
701 1: S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
702 1: return;
703 : }
10: branch 1 taken
3: branch 2 taken
704 13: } else if (isa<BlockDecl>(d)) {
705 : // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
706 : // caller.
707 : ;
10: branch 1 taken
0: branch 2 not taken
708 10: } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
709 10: QualType Ty = V->getType();
5: branch 2 taken
5: branch 3 taken
4: branch 6 taken
1: branch 7 taken
9: branch 8 taken
1: branch 9 taken
710 10: if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
711 : const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
4: branch 2 taken
5: branch 3 taken
712 9: : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
1: branch 2 taken
8: branch 3 taken
713 9: if (!cast<FunctionProtoType>(FT)->isVariadic()) {
0: branch 2 not taken
1: branch 3 taken
714 1: int m = Ty->isFunctionPointerType() ? 0 : 1;
715 1: S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
716 1: return;
717 : }
718 : } else {
719 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
720 1: << Attr.getName() << 6 /*function, method or block */;
721 1: return;
722 : }
723 : } else {
724 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
725 0: << Attr.getName() << 6 /*function, method or block */;
726 0: return;
727 : }
28: branch 1 taken
0: branch 2 not taken
728 28: d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos));
729 : }
730 :
731 13: static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
732 : // check the attribute arguments.
0: branch 1 not taken
13: branch 2 taken
733 13: if (Attr.getNumArgs() != 0) {
734 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
735 0: return;
736 : }
737 :
1: branch 1 taken
12: branch 2 taken
738 13: if (!isFunctionOrMethod(D)) {
739 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
740 1: << Attr.getName() << 0 /*function*/;
741 1: return;
742 : }
743 :
1: branch 4 taken
11: branch 5 taken
744 12: if (getFunctionType(D)->getResultType()->isVoidType()) {
745 : S.Diag(Attr.getLoc(), diag::warn_attribute_void_function)
746 1: << Attr.getName();
747 1: return;
748 : }
749 :
11: branch 1 taken
0: branch 2 not taken
750 11: D->addAttr(::new (S.Context) WarnUnusedResultAttr());
751 : }
752 :
753 21: static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
754 : // check the attribute arguments.
0: branch 1 not taken
21: branch 2 taken
755 21: if (Attr.getNumArgs() != 0) {
756 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
757 0: return;
758 : }
759 :
760 : /* weak only applies to non-static declarations */
761 21: bool isStatic = false;
12: branch 1 taken
9: branch 2 taken
762 21: if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
763 12: isStatic = VD->getStorageClass() == VarDecl::Static;
8: branch 1 taken
1: branch 2 taken
764 9: } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
765 8: isStatic = FD->getStorageClass() == FunctionDecl::Static;
766 : }
1: branch 0 taken
20: branch 1 taken
767 21: if (isStatic) {
768 : S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
769 1: dyn_cast<NamedDecl>(D)->getNameAsString();
770 1: return;
771 : }
772 :
773 : // TODO: could also be applied to methods?
12: branch 1 taken
8: branch 2 taken
1: branch 4 taken
11: branch 5 taken
1: branch 6 taken
19: branch 7 taken
774 20: if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
775 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
776 1: << Attr.getName() << 2 /*variable and function*/;
777 1: return;
778 : }
779 :
19: branch 1 taken
0: branch 2 not taken
780 19: D->addAttr(::new (S.Context) WeakAttr());
781 : }
782 :
783 17: static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
784 : // check the attribute arguments.
0: branch 1 not taken
17: branch 2 taken
785 17: if (Attr.getNumArgs() != 0) {
786 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
787 0: return;
788 : }
789 :
790 : // weak_import only applies to variable & function declarations.
791 17: bool isDef = false;
4: branch 1 taken
13: branch 2 taken
792 17: if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
3: branch 1 taken
1: branch 2 taken
0: branch 4 not taken
3: branch 5 taken
793 4: isDef = (!VD->hasExternalStorage() || VD->getInit());
4: branch 1 taken
9: branch 2 taken
794 13: } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
795 4: isDef = FD->getBody();
8: branch 1 taken
1: branch 2 taken
2: branch 4 taken
6: branch 5 taken
3: branch 6 taken
6: branch 7 taken
796 9: } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) {
797 : // We ignore weak import on properties and methods
798 3: return;
5: branch 0 taken
1: branch 1 taken
0: branch 3 not taken
5: branch 4 taken
1: branch 5 taken
5: branch 6 taken
799 6: } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) {
800 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
801 1: << Attr.getName() << 2 /*variable and function*/;
802 1: return;
803 : }
804 :
805 : // Merge should handle any subsequent violations.
1: branch 0 taken
12: branch 1 taken
806 13: if (isDef) {
807 : S.Diag(Attr.getLoc(),
808 : diag::warn_attribute_weak_import_invalid_on_definition)
809 1: << "weak_import" << 2 /*variable and function*/;
810 1: return;
811 : }
812 :
12: branch 1 taken
0: branch 2 not taken
813 12: D->addAttr(::new (S.Context) WeakImportAttr());
814 : }
815 :
816 7: static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
817 : // check the attribute arguments.
0: branch 1 not taken
7: branch 2 taken
818 7: if (Attr.getNumArgs() != 0) {
819 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
820 0: return;
821 : }
822 :
823 : // Attribute can be applied only to functions or variables.
0: branch 1 not taken
7: branch 2 taken
824 7: if (isa<VarDecl>(D)) {
0: branch 1 not taken
0: branch 2 not taken
825 0: D->addAttr(::new (S.Context) DLLImportAttr());
826 0: return;
827 : }
828 :
829 7: FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
1: branch 0 taken
6: branch 1 taken
830 7: if (!FD) {
831 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
832 1: << Attr.getName() << 2 /*variable and function*/;
833 1: return;
834 : }
835 :
836 : // Currently, the dllimport attribute is ignored for inlined functions.
837 : // Warning is emitted.
1: branch 1 taken
5: branch 2 taken
838 6: if (FD->isInlineSpecified()) {
839 1: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
840 1: return;
841 : }
842 :
843 : // The attribute is also overridden by a subsequent declaration as dllexport.
844 : // Warning is emitted.
0: branch 2 not taken
5: branch 3 taken
845 5: for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
846 : nextAttr = nextAttr->getNext()) {
0: branch 1 not taken
0: branch 2 not taken
847 0: if (nextAttr->getKind() == AttributeList::AT_dllexport) {
848 0: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
849 0: return;
850 : }
851 : }
852 :
2: branch 1 taken
3: branch 2 taken
853 5: if (D->getAttr<DLLExportAttr>()) {
854 2: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
855 2: return;
856 : }
857 :
3: branch 1 taken
0: branch 2 not taken
858 3: D->addAttr(::new (S.Context) DLLImportAttr());
859 : }
860 :
861 6: static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
862 : // check the attribute arguments.
0: branch 1 not taken
6: branch 2 taken
863 6: if (Attr.getNumArgs() != 0) {
864 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
865 0: return;
866 : }
867 :
868 : // Attribute can be applied only to functions or variables.
0: branch 1 not taken
6: branch 2 taken
869 6: if (isa<VarDecl>(D)) {
0: branch 1 not taken
0: branch 2 not taken
870 0: D->addAttr(::new (S.Context) DLLExportAttr());
871 0: return;
872 : }
873 :
874 6: FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
1: branch 0 taken
5: branch 1 taken
875 6: if (!FD) {
876 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
877 1: << Attr.getName() << 2 /*variable and function*/;
878 1: return;
879 : }
880 :
881 : // Currently, the dllexport attribute is ignored for inlined functions, unless
882 : // the -fkeep-inline-functions flag has been used. Warning is emitted;
1: branch 1 taken
4: branch 2 taken
883 5: if (FD->isInlineSpecified()) {
884 : // FIXME: ... unless the -fkeep-inline-functions flag has been used.
885 1: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
886 1: return;
887 : }
888 :
4: branch 1 taken
0: branch 2 not taken
889 4: D->addAttr(::new (S.Context) DLLExportAttr());
890 : }
891 :
892 : static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
893 0: Sema &S) {
894 : // Attribute has 3 arguments.
0: branch 1 not taken
0: branch 2 not taken
895 0: if (Attr.getNumArgs() != 3) {
896 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
897 0: return;
898 : }
899 :
900 : unsigned WGSize[3];
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
0: branch 4 not taken
901 0: for (unsigned i = 0; i < 3; ++i) {
902 0: Expr *E = static_cast<Expr *>(Attr.getArg(i));
903 0: llvm::APSInt ArgNum(32);
0: branch 1 not taken
0: branch 2 not taken
904 0: if (!E->isIntegerConstantExpr(ArgNum, S.Context)) {
905 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
906 0: << "reqd_work_group_size" << E->getSourceRange();
907 0: return;
908 : }
909 0: WGSize[i] = (unsigned) ArgNum.getZExtValue();
910 : }
911 : D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(WGSize[0], WGSize[1],
0: branch 1 not taken
0: branch 2 not taken
912 0: WGSize[2]));
913 : }
914 :
915 14: static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
916 : // Attribute has no arguments.
0: branch 1 not taken
14: branch 2 taken
917 14: if (Attr.getNumArgs() != 1) {
918 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
919 0: return;
920 : }
921 :
922 : // Make sure that there is a string literal as the sections's single
923 : // argument.
924 14: Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
925 14: StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
1: branch 0 taken
13: branch 1 taken
926 14: if (!SE) {
927 1: S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
928 1: return;
929 : }
930 :
931 : // If the target wants to validate the section specifier, make it happen.
932 13: std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString());
1: branch 1 taken
12: branch 2 taken
933 13: if (!Error.empty()) {
934 : S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
935 1: << Error;
936 2: return;
937 : }
938 :
939 : // This attribute cannot be applied to local variables.
10: branch 1 taken
2: branch 2 taken
1: branch 5 taken
9: branch 6 taken
1: branch 7 taken
11: branch 8 taken
940 12: if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) {
941 1: S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
942 : return;
943 : }
944 :
11: branch 2 taken
0: branch 3 not taken
11: branch 7 taken
2: branch 8 taken
945 11: D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
946 : }
947 :
948 :
949 457: static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
950 : // check the attribute arguments.
0: branch 1 not taken
457: branch 2 taken
951 457: if (Attr.getNumArgs() != 0) {
952 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
953 0: return;
954 : }
955 :
457: branch 1 taken
0: branch 2 not taken
956 457: d->addAttr(::new (S.Context) NoThrowAttr());
957 : }
958 :
959 48: static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
960 : // check the attribute arguments.
0: branch 1 not taken
48: branch 2 taken
961 48: if (Attr.getNumArgs() != 0) {
962 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
963 0: return;
964 : }
965 :
48: branch 1 taken
0: branch 2 not taken
966 48: d->addAttr(::new (S.Context) ConstAttr());
967 : }
968 :
969 36: static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
970 : // check the attribute arguments.
0: branch 1 not taken
36: branch 2 taken
971 36: if (Attr.getNumArgs() != 0) {
972 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
973 0: return;
974 : }
975 :
36: branch 1 taken
0: branch 2 not taken
976 36: d->addAttr(::new (S.Context) PureAttr());
977 : }
978 :
979 18: static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
2: branch 1 taken
16: branch 2 taken
980 18: if (!Attr.getParameterName()) {
981 2: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
982 2: return;
983 : }
984 :
0: branch 1 not taken
16: branch 2 taken
985 16: if (Attr.getNumArgs() != 0) {
986 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
987 0: return;
988 : }
989 :
990 16: VarDecl *VD = dyn_cast<VarDecl>(d);
991 :
16: branch 0 taken
0: branch 1 not taken
4: branch 3 taken
12: branch 4 taken
4: branch 5 taken
12: branch 6 taken
992 16: if (!VD || !VD->hasLocalStorage()) {
993 4: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
994 4: return;
995 : }
996 :
997 : // Look up the function
998 : NamedDecl *CleanupDecl
999 : = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
1000 12: Sema::LookupOrdinaryName);
1: branch 0 taken
11: branch 1 taken
1001 12: if (!CleanupDecl) {
1002 : S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
1003 1: Attr.getParameterName();
1004 1: return;
1005 : }
1006 :
1007 11: FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
1: branch 0 taken
10: branch 1 taken
1008 11: if (!FD) {
1009 : S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) <<
1010 1: Attr.getParameterName();
1011 1: return;
1012 : }
1013 :
1: branch 1 taken
9: branch 2 taken
1014 10: if (FD->getNumParams() != 1) {
1015 : S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_must_take_one_arg) <<
1016 1: Attr.getParameterName();
1017 1: return;
1018 : }
1019 :
1020 : // We're currently more strict than GCC about what function types we accept.
1021 : // If this ever proves to be a problem it should be easy to fix.
1022 9: QualType Ty = S.Context.getPointerType(VD->getType());
1023 9: QualType ParamTy = FD->getParamDecl(0)->getType();
1: branch 1 taken
8: branch 2 taken
1024 9: if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) {
1025 : S.Diag(Attr.getLoc(),
1026 : diag::err_attribute_cleanup_func_arg_incompatible_type) <<
1027 1: Attr.getParameterName() << ParamTy << Ty;
1028 1: return;
1029 : }
1030 :
8: branch 1 taken
0: branch 2 not taken
1031 8: d->addAttr(::new (S.Context) CleanupAttr(FD));
1032 : }
1033 :
1034 : /// Handle __attribute__((format_arg((idx)))) attribute based on
1035 : /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
1036 18: static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
4: branch 1 taken
14: branch 2 taken
1037 18: if (Attr.getNumArgs() != 1) {
1038 4: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
1039 4: return;
1040 : }
11: branch 1 taken
3: branch 2 taken
0: branch 4 not taken
11: branch 5 taken
3: branch 6 taken
11: branch 7 taken
1041 14: if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
1042 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1043 3: << Attr.getName() << 0 /*function*/;
1044 3: return;
1045 : }
1046 : // FIXME: in C++ the implicit 'this' function parameter also counts. this is
1047 : // needed in order to be compatible with GCC the index must start with 1.
1048 11: unsigned NumArgs = getFunctionOrMethodNumArgs(d);
1049 11: unsigned FirstIdx = 1;
1050 : // checks for the 2nd argument
1051 11: Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
1052 11: llvm::APSInt Idx(32);
0: branch 1 not taken
11: branch 2 taken
1053 11: if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
1054 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
1055 0: << "format" << 2 << IdxExpr->getSourceRange();
1056 2: return;
1057 : }
1058 :
11: branch 1 taken
0: branch 2 not taken
0: branch 4 not taken
11: branch 5 taken
0: branch 6 not taken
11: branch 7 taken
1059 11: if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
1060 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
1061 0: << "format" << 2 << IdxExpr->getSourceRange();
1062 : return;
1063 : }
1064 :
1065 11: unsigned ArgIdx = Idx.getZExtValue() - 1;
1066 :
1067 : // make sure the format string is really a string
1068 11: QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
1069 :
1070 11: bool not_nsstring_type = !isNSStringType(Ty, S.Context);
3: branch 0 taken
8: branch 1 taken
3: branch 3 taken
0: branch 4 not taken
2: branch 7 taken
1: branch 8 taken
0: branch 14 not taken
2: branch 15 taken
1: branch 16 taken
10: branch 17 taken
1071 11: if (not_nsstring_type &&
1072 : !isCFStringType(Ty, S.Context) &&
1073 : (!Ty->isPointerType() ||
1074 : !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
1075 : // FIXME: Should highlight the actual expression that has the wrong type.
1076 : S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
1077 : << (not_nsstring_type ? "a string type" : "an NSString")
1: branch 1 taken
0: branch 2 not taken
1078 1: << IdxExpr->getSourceRange();
1079 : return;
1080 : }
1081 10: Ty = getFunctionOrMethodResultType(d);
3: branch 1 taken
7: branch 2 taken
3: branch 4 taken
0: branch 5 not taken
2: branch 8 taken
1: branch 9 taken
0: branch 15 not taken
2: branch 16 taken
1: branch 17 taken
9: branch 18 taken
1082 10: if (!isNSStringType(Ty, S.Context) &&
1083 : !isCFStringType(Ty, S.Context) &&
1084 : (!Ty->isPointerType() ||
1085 : !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
1086 : // FIXME: Should highlight the actual expression that has the wrong type.
1087 : S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not)
1088 : << (not_nsstring_type ? "string type" : "NSString")
0: branch 1 not taken
1: branch 2 taken
1089 1: << IdxExpr->getSourceRange();
1090 : return;
1091 : }
1092 :
9: branch 2 taken
0: branch 3 not taken
9: branch 7 taken
2: branch 8 taken
1093 9: d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue()));
1094 : }
1095 :
1096 : enum FormatAttrKind {
1097 : CFStringFormat,
1098 : NSStringFormat,
1099 : StrftimeFormat,
1100 : SupportedFormat,
1101 : InvalidFormat
1102 : };
1103 :
1104 : /// getFormatAttrKind - Map from format attribute names to supported format
1105 : /// types.
1106 75: static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
1107 : // Check for formats that get handled specially.
21: branch 2 taken
54: branch 3 taken
1108 75: if (Format == "NSString")
1109 21: return NSStringFormat;
2: branch 2 taken
52: branch 3 taken
1110 54: if (Format == "CFString")
1111 2: return CFStringFormat;
2: branch 2 taken
50: branch 3 taken
1112 52: if (Format == "strftime")
1113 2: return StrftimeFormat;
1114 :
1115 : // Otherwise, check for supported formats.
38: branch 2 taken
12: branch 3 taken
6: branch 6 taken
32: branch 7 taken
0: branch 10 not taken
6: branch 11 taken
0: branch 14 not taken
0: branch 15 not taken
0: branch 18 not taken
0: branch 19 not taken
0: branch 22 not taken
0: branch 23 not taken
0: branch 26 not taken
0: branch 27 not taken
0: branch 30 not taken
0: branch 31 not taken
0: branch 34 not taken
0: branch 35 not taken
0: branch 38 not taken
0: branch 39 not taken
50: branch 40 taken
0: branch 41 not taken
1116 50: if (Format == "scanf" || Format == "printf" || Format == "printf0" ||
1117 : Format == "strfmon" || Format == "cmn_err" || Format == "strftime" ||
1118 : Format == "NSString" || Format == "CFString" || Format == "vcmn_err" ||
1119 : Format == "zcmn_err")
1120 50: return SupportedFormat;
1121 :
1122 0: return InvalidFormat;
1123 : }
1124 :
1125 : /// Handle __attribute__((format(type,idx,firstarg))) attributes based on
1126 : /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
1127 75: static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1128 :
0: branch 1 not taken
75: branch 2 taken
1129 75: if (!Attr.getParameterName()) {
1130 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
1131 0: << "format" << 1;
1132 0: return;
1133 : }
1134 :
0: branch 1 not taken
75: branch 2 taken
1135 75: if (Attr.getNumArgs() != 2) {
1136 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 3;
1137 0: return;
1138 : }
1139 :
75: branch 1 taken
0: branch 2 not taken
0: branch 4 not taken
75: branch 5 taken
0: branch 6 not taken
75: branch 7 taken
1140 75: if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
1141 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1142 0: << Attr.getName() << 0 /*function*/;
1143 0: return;
1144 : }
1145 :
1146 75: unsigned NumArgs = getFunctionOrMethodNumArgs(d);
1147 75: unsigned FirstIdx = 1;
1148 :
1149 75: llvm::StringRef Format = Attr.getParameterName()->getName();
1150 :
1151 : // Normalize the argument, __foo__ becomes foo.
47: branch 2 taken
28: branch 3 taken
47: branch 6 taken
0: branch 7 not taken
47: branch 8 taken
28: branch 9 taken
1152 75: if (Format.startswith("__") && Format.endswith("__"))
1153 47: Format = Format.substr(2, Format.size() - 4);
1154 :
1155 : // Check for supported formats.
1156 75: FormatAttrKind Kind = getFormatAttrKind(Format);
0: branch 0 not taken
75: branch 1 taken
1157 75: if (Kind == InvalidFormat) {
1158 : S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
1159 0: << "format" << Attr.getParameterName()->getName();
1160 0: return;
1161 : }
1162 :
1163 : // checks for the 2nd argument
1164 75: Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
1165 75: llvm::APSInt Idx(32);
0: branch 1 not taken
75: branch 2 taken
1166 75: if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
1167 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
1168 0: << "format" << 2 << IdxExpr->getSourceRange();
1169 16: return;
1170 : }
1171 :
1172 : // FIXME: We should handle the implicit 'this' parameter in a more generic
1173 : // way that can be used for other arguments.
1174 75: bool HasImplicitThisParam = false;
6: branch 1 taken
69: branch 2 taken
1175 75: if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(d)) {
5: branch 1 taken
1: branch 2 taken
1176 6: if (MD->isInstance()) {
1177 5: HasImplicitThisParam = true;
1178 5: NumArgs++;
1179 : }
1180 : }
1181 :
73: branch 1 taken
2: branch 2 taken
0: branch 4 not taken
73: branch 5 taken
2: branch 6 taken
73: branch 7 taken
1182 75: if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
1183 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
1184 2: << "format" << 2 << IdxExpr->getSourceRange();
1185 : return;
1186 : }
1187 :
1188 : // FIXME: Do we need to bounds check?
1189 73: unsigned ArgIdx = Idx.getZExtValue() - 1;
1190 :
5: branch 0 taken
68: branch 1 taken
1191 73: if (HasImplicitThisParam) {
1: branch 0 taken
4: branch 1 taken
1192 5: if (ArgIdx == 0) {
1193 : S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
1194 1: << "a string type" << IdxExpr->getSourceRange();
1195 : return;
1196 : }
1197 4: ArgIdx--;
1198 : }
1199 :
1200 : // make sure the format string is really a string
1201 72: QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
1202 :
2: branch 0 taken
70: branch 1 taken
1203 72: if (Kind == CFStringFormat) {
1: branch 1 taken
1: branch 2 taken
1204 2: if (!isCFStringType(Ty, S.Context)) {
1205 : S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
1206 1: << "a CFString" << IdxExpr->getSourceRange();
1207 : return;
1208 : }
21: branch 0 taken
49: branch 1 taken
1209 70: } else if (Kind == NSStringFormat) {
1210 : // FIXME: do we need to check if the type is NSString*? What are the
1211 : // semantics?
1: branch 1 taken
20: branch 2 taken
1212 21: if (!isNSStringType(Ty, S.Context)) {
1213 : // FIXME: Should highlight the actual expression that has the wrong type.
1214 : S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
1215 1: << "an NSString" << IdxExpr->getSourceRange();
1216 : return;
1217 : }
43: branch 2 taken
6: branch 3 taken
0: branch 9 not taken
43: branch 10 taken
6: branch 11 taken
43: branch 12 taken
1218 49: } else if (!Ty->isPointerType() ||
1219 : !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
1220 : // FIXME: Should highlight the actual expression that has the wrong type.
1221 : S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
1222 6: << "a string type" << IdxExpr->getSourceRange();
1223 : return;
1224 : }
1225 :
1226 : // check the 3rd argument
1227 64: Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1));
1228 64: llvm::APSInt FirstArg(32);
0: branch 1 not taken
64: branch 2 taken
1229 64: if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
1230 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
1231 0: << "format" << 3 << FirstArgExpr->getSourceRange();
1232 : return;
1233 : }
1234 :
1235 : // check if the function is variadic if the 3rd argument non-zero
42: branch 1 taken
22: branch 2 taken
1236 64: if (FirstArg != 0) {
40: branch 1 taken
2: branch 2 taken
1237 42: if (isFunctionOrMethodVariadic(d)) {
1238 40: ++NumArgs; // +1 for ...
1239 : } else {
1240 2: S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic);
1241 : return;
1242 : }
1243 : }
1244 :
1245 : // strftime requires FirstArg to be 0 because it doesn't read from any
1246 : // variable the input is just the current time + the format string.
2: branch 0 taken
60: branch 1 taken
1247 62: if (Kind == StrftimeFormat) {
1: branch 1 taken
1: branch 2 taken
1248 2: if (FirstArg != 0) {
1249 : S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter)
1250 1: << FirstArgExpr->getSourceRange();
1251 : return;
1252 : }
1253 : // if 0 it disables parameter checking (to use with e.g. va_list)
39: branch 1 taken
21: branch 2 taken
2: branch 4 taken
37: branch 5 taken
2: branch 6 taken
58: branch 7 taken
1254 60: } else if (FirstArg != 0 && FirstArg != NumArgs) {
1255 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
1256 2: << "format" << 3 << FirstArgExpr->getSourceRange();
1257 : return;
1258 : }
1259 :
1260 : d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(),
59: branch 3 taken
0: branch 4 not taken
59: branch 8 taken
5: branch 9 taken
59: branch 11 taken
16: branch 12 taken
1261 59: FirstArg.getZExtValue()));
1262 : }
1263 :
1264 : static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
1265 6: Sema &S) {
1266 : // check the attribute arguments.
0: branch 1 not taken
6: branch 2 taken
1267 6: if (Attr.getNumArgs() != 0) {
1268 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1269 0: return;
1270 : }
1271 :
1272 : // Try to find the underlying union declaration.
1273 6: RecordDecl *RD = 0;
1274 6: TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
6: branch 0 taken
0: branch 1 not taken
6: branch 5 taken
0: branch 6 not taken
6: branch 7 taken
0: branch 8 not taken
1275 6: if (TD && TD->getUnderlyingType()->isUnionType())
1276 6: RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
1277 : else
1278 0: RD = dyn_cast<RecordDecl>(d);
1279 :
6: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
6: branch 4 taken
0: branch 5 not taken
6: branch 6 taken
1280 6: if (!RD || !RD->isUnion()) {
1281 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1282 0: << Attr.getName() << 1 /*union*/;
1283 0: return;
1284 : }
1285 :
0: branch 1 not taken
6: branch 2 taken
1286 6: if (!RD->isDefinition()) {
1287 : S.Diag(Attr.getLoc(),
1288 0: diag::warn_transparent_union_attribute_not_definition);
1289 0: return;
1290 : }
1291 :
1292 6: RecordDecl::field_iterator Field = RD->field_begin(),
1293 6: FieldEnd = RD->field_end();
1: branch 1 taken
5: branch 2 taken
1294 6: if (Field == FieldEnd) {
1295 1: S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields);
1296 1: return;
1297 : }
1298 :
1299 5: FieldDecl *FirstField = *Field;
1300 5: QualType FirstType = FirstField->getType();
4: branch 2 taken
1: branch 3 taken
0: branch 6 not taken
4: branch 7 taken
1: branch 8 taken
4: branch 9 taken
1301 5: if (FirstType->isFloatingType() || FirstType->isVectorType()) {
1302 : S.Diag(FirstField->getLocation(),
1303 1: diag::warn_transparent_union_attribute_floating);
1304 1: return;
1305 : }
1306 :
1307 4: uint64_t FirstSize = S.Context.getTypeSize(FirstType);
1308 4: uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
8: branch 2 taken
2: branch 3 taken
1309 10: for (; Field != FieldEnd; ++Field) {
1310 8: QualType FieldType = Field->getType();
7: branch 1 taken
1: branch 2 taken
1: branch 4 taken
6: branch 5 taken
2: branch 6 taken
6: branch 7 taken
1311 8: if (S.Context.getTypeSize(FieldType) != FirstSize ||
1312 : S.Context.getTypeAlign(FieldType) != FirstAlign) {
1313 : // Warn if we drop the attribute.
1314 2: bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
1315 : unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
1: branch 0 taken
1: branch 1 taken
1316 2: : S.Context.getTypeAlign(FieldType);
1317 : S.Diag(Field->getLocation(),
1318 : diag::warn_transparent_union_attribute_field_size_align)
1319 2: << isSize << Field->getDeclName() << FieldBits;
1: branch 0 taken
1: branch 1 taken
1320 2: unsigned FirstBits = isSize? FirstSize : FirstAlign;
1321 : S.Diag(FirstField->getLocation(),
1322 : diag::note_transparent_union_first_field_size_align)
1323 2: << isSize << FirstBits;
1324 2: return;
1325 : }
1326 : }
1327 :
2: branch 1 taken
0: branch 2 not taken
1328 2: RD->addAttr(::new (S.Context) TransparentUnionAttr());
1329 : }
1330 :
1331 6: static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1332 : // check the attribute arguments.
1: branch 1 taken
5: branch 2 taken
1333 6: if (Attr.getNumArgs() != 1) {
1334 1: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
1335 1: return;
1336 : }
1337 5: Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
1338 5: StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
1339 :
1340 : // Make sure that there is a string literal as the annotation's single
1341 : // argument.
1: branch 0 taken
4: branch 1 taken
1342 5: if (!SE) {
1343 1: S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
1344 1: return;
1345 : }
4: branch 2 taken
0: branch 3 not taken
1346 4: d->addAttr(::new (S.Context) AnnotateAttr(SE->getString()));
1347 : }
1348 :
1349 53: static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1350 : // check the attribute arguments.
0: branch 1 not taken
53: branch 2 taken
1351 53: if (Attr.getNumArgs() > 1) {
1352 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
1353 0: return;
1354 : }
1355 :
1356 : //FIXME: The C++0x version of this attribute has more limited applicabilty
1357 : // than GNU's, and should error out when it is used to specify a
1358 : // weaker alignment, rather than being silently ignored.
1359 :
1360 53: unsigned Align = 0;
2: branch 1 taken
51: branch 2 taken
1361 53: if (Attr.getNumArgs() == 0) {
1362 : // FIXME: This should be the target specific maximum alignment.
1363 : // (For now we just use 128 bits which is the maximum on X86).
1364 2: Align = 128;
2: branch 1 taken
0: branch 2 not taken
1365 2: d->addAttr(::new (S.Context) AlignedAttr(Align));
1366 2: return;
1367 : }
1368 :
1369 51: Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
1370 51: llvm::APSInt Alignment(32);
1: branch 1 taken
50: branch 2 taken
1371 51: if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
1372 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
1373 1: << "aligned" << alignmentExpr->getSourceRange();
1374 3: return;
1375 : }
2: branch 2 taken
48: branch 3 taken
1376 50: if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
1377 : S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
1378 2: << alignmentExpr->getSourceRange();
1379 : return;
1380 : }
1381 :
48: branch 2 taken
0: branch 3 not taken
48: branch 7 taken
3: branch 8 taken
1382 48: d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8));
1383 : }
1384 :
1385 : /// HandleModeAttr - This attribute modifies the width of a decl with primitive
1386 : /// type.
1387 : ///
1388 : /// Despite what would be logical, the mode attribute is a decl attribute, not a
1389 : /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
1390 : /// HImode, not an intermediate pointer.
1391 104: static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
1392 : // This attribute isn't documented, but glibc uses it. It changes
1393 : // the width of an int or unsigned int to the specified size.
1394 :
1395 : // Check that there aren't any arguments
0: branch 1 not taken
104: branch 2 taken
1396 104: if (Attr.getNumArgs() != 0) {
1397 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1398 0: return;
1399 : }
1400 :
1401 104: IdentifierInfo *Name = Attr.getParameterName();
4: branch 0 taken
100: branch 1 taken
1402 104: if (!Name) {
1403 4: S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name);
1404 4: return;
1405 : }
1406 :
1407 100: llvm::StringRef Str = Attr.getParameterName()->getName();
1408 :
1409 : // Normalize the attribute name, __foo__ becomes foo.
80: branch 2 taken
20: branch 3 taken
80: branch 6 taken
0: branch 7 not taken
80: branch 8 taken
20: branch 9 taken
1410 100: if (Str.startswith("__") && Str.endswith("__"))
1411 80: Str = Str.substr(2, Str.size() - 4);
1412 :
1413 100: unsigned DestWidth = 0;
1414 100: bool IntegerMode = true;
1415 100: bool ComplexMode = false;
94: branch 1 taken
6: branch 2 taken
0: branch 3 not taken
0: branch 4 not taken
1416 100: switch (Str.size()) {
1417 : case 2:
18: branch 1 taken
24: branch 2 taken
26: branch 3 taken
20: branch 4 taken
2: branch 5 taken
2: branch 6 taken
2: branch 7 taken
1418 94: switch (Str[0]) {
1419 18: case 'Q': DestWidth = 8; break;
1420 24: case 'H': DestWidth = 16; break;
1421 26: case 'S': DestWidth = 32; break;
1422 20: case 'D': DestWidth = 64; break;
1423 2: case 'X': DestWidth = 96; break;
1424 2: case 'T': DestWidth = 128; break;
1425 : }
2: branch 1 taken
92: branch 2 taken
1426 94: if (Str[1] == 'F') {
1427 2: IntegerMode = false;
6: branch 1 taken
86: branch 2 taken
1428 92: } else if (Str[1] == 'C') {
1429 6: IntegerMode = false;
1430 6: ComplexMode = true;
0: branch 1 not taken
86: branch 2 taken
1431 86: } else if (Str[1] != 'I') {
1432 0: DestWidth = 0;
1433 : }
1434 94: break;
1435 : case 4:
1436 : // FIXME: glibc uses 'word' to define register_t; this is narrower than a
1437 : // pointer on PIC16 and other embedded platforms.
6: branch 2 taken
0: branch 3 not taken
1438 6: if (Str == "word")
1439 6: DestWidth = S.Context.Target.getPointerWidth(0);
0: branch 2 not taken
0: branch 3 not taken
1440 0: else if (Str == "byte")
1441 0: DestWidth = S.Context.Target.getCharWidth();
1442 6: break;
1443 : case 7:
0: branch 2 not taken
0: branch 3 not taken
1444 0: if (Str == "pointer")
1445 0: DestWidth = S.Context.Target.getPointerWidth(0);
1446 : break;
1447 : }
1448 :
1449 100: QualType OldTy;
98: branch 1 taken
2: branch 2 taken
1450 100: if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
1451 98: OldTy = TD->getUnderlyingType();
2: branch 1 taken
0: branch 2 not taken
1452 2: else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
1453 2: OldTy = VD->getType();
1454 : else {
1455 : S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
1456 0: << "mode" << SourceRange(Attr.getLoc(), Attr.getLoc());
1457 0: return;
1458 : }
1459 :
10: branch 2 taken
90: branch 3 taken
4: branch 6 taken
6: branch 7 taken
4: branch 8 taken
96: branch 9 taken
1460 100: if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType())
1461 4: S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
88: branch 0 taken
8: branch 1 taken
1462 96: else if (IntegerMode) {
2: branch 2 taken
86: branch 3 taken
1463 88: if (!OldTy->isIntegralType())
1464 2: S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
6: branch 0 taken
2: branch 1 taken
1465 8: } else if (ComplexMode) {
0: branch 2 not taken
6: branch 3 taken
1466 6: if (!OldTy->isComplexType())
1467 0: S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
1468 : } else {
0: branch 2 not taken
2: branch 3 taken
1469 2: if (!OldTy->isFloatingType())
1470 0: S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
1471 : }
1472 :
1473 : // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
1474 : // and friends, at least with glibc.
1475 : // FIXME: Make sure 32/64-bit integers don't get defined to types of the wrong
1476 : // width on unusual platforms.
1477 : // FIXME: Make sure floating-point mappings are accurate
1478 : // FIXME: Support XF and TF types
1479 100: QualType NewTy;
2: branch 0 taken
0: branch 1 not taken
18: branch 2 taken
24: branch 3 taken
32: branch 4 taken
20: branch 5 taken
2: branch 6 taken
2: branch 7 taken
1480 100: switch (DestWidth) {
1481 : case 0:
1482 2: S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name;
1483 2: return;
1484 : default:
1485 0: S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
1486 0: return;
1487 : case 8:
0: branch 0 not taken
18: branch 1 taken
1488 18: if (!IntegerMode) {
1489 0: S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
1490 0: return;
1491 : }
8: branch 2 taken
10: branch 3 taken
1492 18: if (OldTy->isSignedIntegerType())
1493 8: NewTy = S.Context.SignedCharTy;
1494 : else
1495 10: NewTy = S.Context.UnsignedCharTy;
1496 18: break;
1497 : case 16:
0: branch 0 not taken
24: branch 1 taken
1498 24: if (!IntegerMode) {
1499 0: S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
1500 0: return;
1501 : }
14: branch 2 taken
10: branch 3 taken
1502 24: if (OldTy->isSignedIntegerType())
1503 14: NewTy = S.Context.ShortTy;
1504 : else
1505 10: NewTy = S.Context.UnsignedShortTy;
1506 24: break;
1507 : case 32:
2: branch 0 taken
30: branch 1 taken
1508 32: if (!IntegerMode)
1509 2: NewTy = S.Context.FloatTy;
16: branch 2 taken
14: branch 3 taken
1510 30: else if (OldTy->isSignedIntegerType())
1511 16: NewTy = S.Context.IntTy;
1512 : else
1513 14: NewTy = S.Context.UnsignedIntTy;
1514 32: break;
1515 : case 64:
4: branch 0 taken
16: branch 1 taken
1516 20: if (!IntegerMode)
1517 4: NewTy = S.Context.DoubleTy;
8: branch 2 taken
8: branch 3 taken
1518 16: else if (OldTy->isSignedIntegerType())
1: branch 1 taken
7: branch 2 taken
1519 8: if (S.Context.Target.getLongWidth() == 64)
1520 1: NewTy = S.Context.LongTy;
1521 : else
1522 7: NewTy = S.Context.LongLongTy;
1523 : else
1: branch 1 taken
7: branch 2 taken
1524 8: if (S.Context.Target.getLongWidth() == 64)
1525 1: NewTy = S.Context.UnsignedLongTy;
1526 : else
1527 7: NewTy = S.Context.UnsignedLongLongTy;
1528 20: break;
1529 : case 96:
1530 2: NewTy = S.Context.LongDoubleTy;
1531 2: break;
1532 : case 128:
0: branch 0 not taken
2: branch 1 taken
1533 2: if (!IntegerMode) {
1534 0: S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
1535 0: return;
1536 : }
1: branch 2 taken
1: branch 3 taken
1537 2: if (OldTy->isSignedIntegerType())
1538 1: NewTy = S.Context.Int128Ty;
1539 : else
1540 1: NewTy = S.Context.UnsignedInt128Ty;
1541 : break;
1542 : }
1543 :
6: branch 0 taken
92: branch 1 taken
1544 98: if (ComplexMode) {
1545 6: NewTy = S.Context.getComplexType(NewTy);
1546 : }
1547 :
1548 : // Install the new type.
96: branch 1 taken
2: branch 2 taken
1549 98: if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
1550 : // FIXME: preserve existing source info.
1551 96: TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy));
1552 : } else
1553 2: cast<ValueDecl>(D)->setType(NewTy);
1554 : }
1555 :
1556 1247: static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1557 : // check the attribute arguments.
1: branch 1 taken
1246: branch 2 taken
1558 1247: if (Attr.getNumArgs() > 0) {
1559 1: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1560 1: return;
1561 : }
1562 :
1: branch 1 taken
1245: branch 2 taken
1563 1246: if (!isFunctionOrMethod(d)) {
1564 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1565 1: << Attr.getName() << 0 /*function*/;
1566 1: return;
1567 : }
1568 :
1245: branch 1 taken
0: branch 2 not taken
1569 1245: d->addAttr(::new (S.Context) NoDebugAttr());
1570 : }
1571 :
1572 10: static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1573 : // check the attribute arguments.
1: branch 1 taken
9: branch 2 taken
1574 10: if (Attr.getNumArgs() != 0) {
1575 1: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1576 1: return;
1577 : }
1578 :
1: branch 1 taken
8: branch 2 taken
1579 9: if (!isa<FunctionDecl>(d)) {
1580 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1581 1: << Attr.getName() << 0 /*function*/;
1582 1: return;
1583 : }
1584 :
8: branch 1 taken
0: branch 2 not taken
1585 8: d->addAttr(::new (S.Context) NoInlineAttr());
1586 : }
1587 :
1588 23: static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1589 : // check the attribute arguments.
0: branch 1 not taken
23: branch 2 taken
1590 23: if (Attr.getNumArgs() != 0) {
1591 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1592 0: return;
1593 : }
1594 :
1595 23: FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
0: branch 0 not taken
23: branch 1 taken
1596 23: if (Fn == 0) {
1597 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1598 0: << Attr.getName() << 0 /*function*/;
1599 0: return;
1600 : }
1601 :
1: branch 1 taken
22: branch 2 taken
1602 23: if (!Fn->isInlineSpecified()) {
1603 1: S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
1604 1: return;
1605 : }
1606 :
22: branch 1 taken
0: branch 2 not taken
1607 22: d->addAttr(::new (S.Context) GNUInlineAttr());
1608 : }
1609 :
1610 7: static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1611 : // check the attribute arguments.
1: branch 1 taken
6: branch 2 taken
1612 7: if (Attr.getNumArgs() != 1) {
1613 1: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
1614 1: return;
1615 : }
1616 :
0: branch 1 not taken
6: branch 2 taken
1617 6: if (!isFunctionOrMethod(d)) {
1618 : S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
1619 0: << Attr.getName() << 0 /*function*/;
1620 0: return;
1621 : }
1622 :
1623 6: Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
1624 6: llvm::APSInt NumParams(32);
1: branch 1 taken
5: branch 2 taken
1625 6: if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
1626 : S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
1627 1: << "regparm" << NumParamsExpr->getSourceRange();
1628 3: return;
1629 : }
1630 :
0: branch 1 not taken
5: branch 2 taken
1631 5: if (S.Context.Target.getRegParmMax() == 0) {
1632 : S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
1633 0: << NumParamsExpr->getSourceRange();
1634 : return;
1635 : }
1636 :
2: branch 2 taken
3: branch 3 taken
1637 5: if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) {
1638 : S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
1639 2: << S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
1640 : return;
1641 : }
1642 :
3: branch 2 taken
0: branch 3 not taken
3: branch 7 taken
3: branch 8 taken
1643 3: d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
1644 : }
1645 :
1646 3: static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
1647 : // check the attribute arguments.
0: branch 1 not taken
3: branch 2 taken
1648 3: if (Attr.getNumArgs() != 0) {
1649 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1650 0: return;
1651 : }
1652 :
2: branch 1 taken
1: branch 2 taken
1: branch 4 taken
1: branch 5 taken
0: branch 8 not taken
1: branch 9 taken
1: branch 10 taken
2: branch 11 taken
1653 3: if (!isa<CXXRecordDecl>(d)
1654 : && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual())) {
1655 : S.Diag(Attr.getLoc(),
1656 : Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
1657 : : diag::warn_attribute_wrong_decl_type)
1: branch 2 taken
0: branch 3 not taken
1658 1: << Attr.getName() << 7 /*virtual method or class*/;
1659 1: return;
1660 : }
1661 :
1662 : // FIXME: Conform to C++0x redeclaration rules.
1663 :
0: branch 1 not taken
2: branch 2 taken
1664 2: if (d->getAttr<FinalAttr>()) {
1665 0: S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "final";
1666 0: return;
1667 : }
1668 :
2: branch 1 taken
0: branch 2 not taken
1669 2: d->addAttr(::new (S.Context) FinalAttr());
1670 : }
1671 :
1672 : //===----------------------------------------------------------------------===//
1673 : // C++0x member checking attributes
1674 : //===----------------------------------------------------------------------===//
1675 :
1676 3: static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
3: branch 2 taken
1677 3: if (Attr.getNumArgs() != 0) {
1678 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1679 0: return;
1680 : }
1681 :
1: branch 1 taken
2: branch 2 taken
1682 3: if (!isa<CXXRecordDecl>(d)) {
1683 : S.Diag(Attr.getLoc(),
1684 : Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
1685 : : diag::warn_attribute_wrong_decl_type)
1: branch 2 taken
0: branch 3 not taken
1686 1: << Attr.getName() << 9 /*class*/;
1687 1: return;
1688 : }
1689 :
1: branch 1 taken
1: branch 2 taken
1690 2: if (d->getAttr<BaseCheckAttr>()) {
1691 1: S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "base_check";
1692 1: return;
1693 : }
1694 :
1: branch 1 taken
0: branch 2 not taken
1695 1: d->addAttr(::new (S.Context) BaseCheckAttr());
1696 : }
1697 :
1698 1: static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
1: branch 2 taken
1699 1: if (Attr.getNumArgs() != 0) {
1700 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1701 0: return;
1702 : }
1703 :
1: branch 2 taken
0: branch 3 not taken
1704 1: if (!isa<RecordDecl>(d->getDeclContext())) {
1705 : // FIXME: It's not the type that's the problem
1706 : S.Diag(Attr.getLoc(),
1707 : Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
1708 : : diag::warn_attribute_wrong_decl_type)
1: branch 2 taken
0: branch 3 not taken
1709 1: << Attr.getName() << 11 /*member*/;
1710 1: return;
1711 : }
1712 :
1713 : // FIXME: Conform to C++0x redeclaration rules.
1714 :
0: branch 1 not taken
0: branch 2 not taken
1715 0: if (d->getAttr<HidingAttr>()) {
1716 0: S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "hiding";
1717 0: return;
1718 : }
1719 :
0: branch 1 not taken
0: branch 2 not taken
1720 0: d->addAttr(::new (S.Context) HidingAttr());
1721 : }
1722 :
1723 1: static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) {
0: branch 1 not taken
1: branch 2 taken
1724 1: if (Attr.getNumArgs() != 0) {
1725 0: S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
1726 0: return;
1727 : }
1728 :
0: branch 1 not taken
1: branch 2 taken
0: branch 5 not taken
0: branch 6 not taken
1: branch 7 taken
0: branch 8 not taken
1729 1: if (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual()) {
1730 : // FIXME: It's not the type that's the problem
1731 : S.Diag(Attr.getLoc(),
1732 : Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
1733 : : diag::warn_attribute_wrong_decl_type)
1: branch 2 taken
0: branch 3 not taken
1734 1: << Attr.getName() << 10 /*virtual method*/;
1735 1: return;
1736 : }
1737 :
1738 : // FIXME: Conform to C++0x redeclaration rules.
1739 :
0: branch 1 not taken
0: branch 2 not taken
1740 0: if (d->getAttr<OverrideAttr>()) {
1741 0: S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "override";
1742 0: return;
1743 : }
1744 :
0: branch 1 not taken
0: branch 2 not taken
1745 0: d->addAttr(::new (S.Context) OverrideAttr());
1746 : }
1747 :
1748 : //===----------------------------------------------------------------------===//
1749 : // Checker-specific attribute handlers.
1750 : //===----------------------------------------------------------------------===//
1751 :
1752 : static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
1753 30: Sema &S) {
1754 :
1755 30: QualType RetTy;
1756 :
22: branch 1 taken
8: branch 2 taken
1757 30: if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
1758 22: RetTy = MD->getResultType();
6: branch 1 taken
2: branch 2 taken
1759 8: else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
1760 6: RetTy = FD->getResultType();
1761 : else {
1762 2: SourceLocation L = Attr.getLoc();
1763 : S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
1764 2: << SourceRange(L, L) << Attr.getName() << 3 /* function or method */;
1765 2: return;
1766 : }
1767 :
28: branch 1 taken
0: branch 2 not taken
20: branch 5 taken
8: branch 6 taken
2: branch 9 taken
18: branch 10 taken
2: branch 11 taken
26: branch 12 taken
1768 28: if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
1769 : || RetTy->getAs<ObjCObjectPointerType>())) {
1770 2: SourceLocation L = Attr.getLoc();
1771 : S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
1772 2: << SourceRange(L, L) << Attr.getName();
1773 2: return;
1774 : }
1775 :
0: branch 1 not taken
16: branch 2 taken
10: branch 3 taken
1776 26: switch (Attr.getKind()) {
1777 : default:
1778 0: assert(0 && "invalid ownership attribute");
1779 : return;
1780 : case AttributeList::AT_cf_returns_retained:
16: branch 1 taken
0: branch 2 not taken
1781 16: d->addAttr(::new (S.Context) CFReturnsRetainedAttr());
1782 16: return;
1783 : case AttributeList::AT_ns_returns_retained:
10: branch 1 taken
0: branch 2 not taken
1784 10: d->addAttr(::new (S.Context) NSReturnsRetainedAttr());
1785 10: return;
1786 : };
1787 : }
1788 :
1789 : //===----------------------------------------------------------------------===//
1790 : // Top Level Sema Entry Points
1791 : //===----------------------------------------------------------------------===//
1792 :
1793 : /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
1794 : /// the attribute applies to decls. If the attribute is a type attribute, just
1795 : /// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
1796 : /// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
1797 : static void ProcessDeclAttribute(Scope *scope, Decl *D,
1798 4890: const AttributeList &Attr, Sema &S) {
23: branch 1 taken
4867: branch 2 taken
1799 4890: if (Attr.isDeclspecAttribute())
1800 : // FIXME: Try to deal with __declspec attributes!
1801 23: return;
1: branch 1 taken
323: branch 2 taken
11: branch 3 taken
53: branch 4 taken
1279: branch 5 taken
8: branch 6 taken
6: branch 7 taken
3: branch 8 taken
0: branch 9 not taken
8: branch 10 taken
46: branch 11 taken
7: branch 12 taken
6: branch 13 taken
7: branch 14 taken
65: branch 15 taken
3: branch 16 taken
75: branch 17 taken
18: branch 18 taken
23: branch 19 taken
1: branch 20 taken
104: branch 21 taken
46: branch 22 taken
409: branch 23 taken
105: branch 24 taken
457: branch 25 taken
1: branch 26 taken
30: branch 27 taken
0: branch 28 not taken
26: branch 29 taken
14: branch 30 taken
9: branch 31 taken
24: branch 32 taken
16: branch 33 taken
14: branch 34 taken
13: branch 35 taken
21: branch 36 taken
17: branch 37 taken
6: branch 38 taken
7: branch 39 taken
35: branch 40 taken
4: branch 41 taken
112: branch 42 taken
40: branch 43 taken
48: branch 44 taken
36: branch 45 taken
18: branch 46 taken
1247: branch 47 taken
10: branch 48 taken
7: branch 49 taken
16: branch 50 taken
30: branch 51 taken
2: branch 52 taken
1802 4867: switch (Attr.getKind()) {
1803 1: case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
1804 : case AttributeList::AT_address_space:
1805 : case AttributeList::AT_objc_gc:
1806 : case AttributeList::AT_vector_size:
1807 : // Ignore these, these are type attributes, handled by
1808 : // ProcessTypeAttributes.
1809 323: break;
1810 11: case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
1811 53: case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
1812 : case AttributeList::AT_always_inline:
1813 1279: HandleAlwaysInlineAttr (D, Attr, S); break;
1814 : case AttributeList::AT_analyzer_noreturn:
1815 8: HandleAnalyzerNoReturnAttr (D, Attr, S); break;
1816 6: case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
1817 3: case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break;
1818 : case AttributeList::AT_carries_dependency:
1819 0: HandleDependencyAttr (D, Attr, S); break;
1820 8: case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
1821 46: case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
1822 7: case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
1823 6: case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break;
1824 7: case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break;
1825 : case AttributeList::AT_ext_vector_type:
1826 65: HandleExtVectorTypeAttr(scope, D, Attr, S);
1827 65: break;
1828 3: case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
1829 75: case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
1830 18: case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
1831 23: case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break;
1832 1: case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break;
1833 104: case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
1834 46: case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
1835 409: case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
1836 105: case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
1837 457: case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
1838 1: case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break;
1839 :
1840 : // Checker-specific.
1841 : case AttributeList::AT_ns_returns_retained:
1842 : case AttributeList::AT_cf_returns_retained:
1843 30: HandleNSReturnsRetainedAttr(D, Attr, S); break;
1844 :
1845 : case AttributeList::AT_reqd_wg_size:
1846 0: HandleReqdWorkGroupSize(D, Attr, S); break;
1847 :
1848 26: case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
1849 14: case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
1850 9: case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
1851 24: case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
1852 16: case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
1853 14: case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break;
1854 13: case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
1855 13: break;
1856 21: case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
1857 17: case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break;
1858 : case AttributeList::AT_transparent_union:
1859 6: HandleTransparentUnionAttr(D, Attr, S);
1860 6: break;
1861 : case AttributeList::AT_objc_exception:
1862 7: HandleObjCExceptionAttr(D, Attr, S);
1863 7: break;
1864 35: case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
1865 4: case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
1866 112: case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
1867 40: case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
1868 48: case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
1869 36: case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
1870 18: case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
1871 1247: case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
1872 10: case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
1873 7: case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
1874 : case AttributeList::IgnoredAttribute:
1875 : case AttributeList::AT_no_instrument_function: // Interacts with -pg.
1876 : // Just ignore
1877 16: break;
1878 : case AttributeList::AT_stdcall:
1879 : case AttributeList::AT_cdecl:
1880 : case AttributeList::AT_fastcall:
1881 : // These are all treated as type attributes.
1882 30: break;
1883 : default:
1884 : // Ask target about the attribute.
1885 2: const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
2: branch 1 taken
0: branch 2 not taken
1886 2: if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
1887 2: S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
1888 : break;
1889 : }
1890 : }
1891 :
1892 : /// ProcessDeclAttributeList - Apply all the decl attributes in the specified
1893 : /// attribute list to the specified decl, ignoring any type attributes.
1894 5715: void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) {
4890: branch 0 taken
5715: branch 1 taken
1895 16320: while (AttrList) {
1896 4890: ProcessDeclAttribute(S, D, *AttrList, *this);
1897 4890: AttrList = AttrList->getNext();
1898 : }
1899 5715: }
1900 :
1901 : /// DeclClonePragmaWeak - clone existing decl (maybe definition),
1902 : /// #pragma weak needs a non-definition decl and source may not have one
1903 15: NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
1: branch 1 taken
14: branch 2 taken
0: branch 4 not taken
1: branch 5 taken
1904 15: assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
1905 15: NamedDecl *NewD = 0;
14: branch 1 taken
1: branch 2 taken
1906 15: if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
1907 : NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
1908 : FD->getLocation(), DeclarationName(II),
1909 14: FD->getType(), FD->getTypeSourceInfo());
1: branch 1 taken
0: branch 2 not taken
1910 1: } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
1911 : NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
1912 : VD->getLocation(), II,
1913 : VD->getType(), VD->getTypeSourceInfo(),
1914 1: VD->getStorageClass());
1915 : }
1916 15: return NewD;
1917 : }
1918 :
1919 : /// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
1920 : /// applied to it, possibly with an alias.
1921 21: void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
19: branch 1 taken
2: branch 2 taken
1922 21: if (W.getUsed()) return; // only do this once
1923 19: W.setUsed(true);
15: branch 1 taken
4: branch 2 taken
1924 19: if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
1925 15: IdentifierInfo *NDId = ND->getIdentifier();
1926 15: NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
15: branch 2 taken
0: branch 3 not taken
1927 15: NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
15: branch 1 taken
0: branch 2 not taken
1928 15: NewD->addAttr(::new (Context) WeakAttr());
1929 15: WeakTopLevelDecl.push_back(NewD);
1930 : // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
1931 : // to insert Decl at TU scope, sorry.
1932 15: DeclContext *SavedContext = CurContext;
15: branch 1 taken
0: branch 2 not taken
1933 15: CurContext = Context.getTranslationUnitDecl();
1934 15: PushOnScopeChains(NewD, S);
1935 15: CurContext = SavedContext;
1936 : } else { // just add weak to existing
4: branch 1 taken
0: branch 2 not taken
1937 4: ND->addAttr(::new (Context) WeakAttr());
1938 : }
1939 : }
1940 :
1941 : /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
1942 : /// it, apply them to D. This is a bit tricky because PD can have attributes
1943 : /// specified in many different places, and we need to find and apply them all.
1944 49447: void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
1945 : // Handle #pragma weak
49184: branch 1 taken
263: branch 2 taken
1946 49447: if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
30680: branch 1 taken
18504: branch 2 taken
1947 49184: if (ND->hasLinkage()) {
1948 30680: WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier());
12: branch 2 taken
30668: branch 3 taken
1949 30680: if (W != WeakInfo()) {
1950 : // Identifier referenced by #pragma weak before it was declared
1951 12: DeclApplyPragmaWeak(S, ND, W);
1952 12: WeakUndeclaredIdentifiers[ND->getIdentifier()] = W;
1953 : }
1954 : }
1955 : }
1956 :
1957 : // Apply decl attributes from the DeclSpec if present.
1744: branch 2 taken
47703: branch 3 taken
1958 49447: if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
1959 1744: ProcessDeclAttributeList(S, D, Attrs);
1960 :
1961 : // Walk the declarator structure, applying decl attributes that were in a type
1962 : // position to the decl itself. This handles cases like:
1963 : // int *__attr__(x)** D;
1964 : // when X is a decl attribute.
30208: branch 1 taken
49447: branch 2 taken
1965 79655: for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
31: branch 2 taken
30177: branch 3 taken
1966 30208: if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
1967 31: ProcessDeclAttributeList(S, D, Attrs);
1968 :
1969 : // Finally, apply any attributes on the decl itself.
1386: branch 1 taken
48061: branch 2 taken
1970 49447: if (const AttributeList *Attrs = PD.getAttributes())
1971 1386: ProcessDeclAttributeList(S, D, Attrs);
1972 49447: }
1973 :
1974 : /// PushParsingDeclaration - Enter a new "scope" of deprecation
1975 : /// warnings.
1976 : ///
1977 : /// The state token we use is the start index of this scope
1978 : /// on the warning stack.
1979 74476: Action::ParsingDeclStackState Sema::PushParsingDeclaration() {
1980 74476: ParsingDeclDepth++;
1981 74476: return (ParsingDeclStackState) DelayedDiagnostics.size();
1982 : }
1983 :
1984 74476: void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
0: branch 0 not taken
74476: branch 1 taken
1985 74476: assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
1986 74476: ParsingDeclDepth--;
1987 :
74434: branch 1 taken
42: branch 2 taken
1988 74476: if (DelayedDiagnostics.empty())
1989 74434: return;
1990 :
1991 42: unsigned SavedIndex = (unsigned) S;
1992 : assert(SavedIndex <= DelayedDiagnostics.size() &&
42: branch 1 taken
0: branch 2 not taken
1993 42: "saved index is out of bounds");
1994 :
1995 : // We only want to actually emit delayed diagnostics when we
1996 : // successfully parsed a decl.
30: branch 1 taken
12: branch 2 taken
1997 72: Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
30: branch 0 taken
12: branch 1 taken
1998 42: if (D) {
1999 : // We really do want to start with 0 here. We get one push for a
2000 : // decl spec and another for each declarator; in a decl group like:
2001 : // deprecated_typedef foo, *bar, baz();
2002 : // only the declarator pops will be passed decls. This is correct;
2003 : // we really do need to consider delayed diagnostics from the decl spec
2004 : // for each of the different declarations.
33: branch 1 taken
30: branch 2 taken
2005 63: for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) {
2: branch 1 taken
31: branch 2 taken
2006 33: if (DelayedDiagnostics[I].Triggered)
2007 2: continue;
2008 :
25: branch 1 taken
6: branch 2 taken
0: branch 3 not taken
2009 31: switch (DelayedDiagnostics[I].Kind) {
2010 : case DelayedDiagnostic::Deprecation:
2011 25: HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D);
2012 25: break;
2013 :
2014 : case DelayedDiagnostic::Access:
2015 6: HandleDelayedAccessCheck(DelayedDiagnostics[I], D);
2016 : break;
2017 : }
2018 : }
2019 : }
2020 :
2021 42: DelayedDiagnostics.set_size(SavedIndex);
2022 : }
2023 :
2024 133: static bool isDeclDeprecated(Decl *D) {
60: branch 2 taken
51: branch 3 taken
2025 111: do {
22: branch 1 taken
111: branch 2 taken
2026 133: if (D->hasAttr<DeprecatedAttr>())
2027 22: return true;
2028 : } while ((D = cast_or_null<Decl>(D->getDeclContext())));
2029 51: return false;
2030 : }
2031 :
2032 : void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD,
2033 25: Decl *Ctx) {
11: branch 1 taken
14: branch 2 taken
2034 25: if (isDeclDeprecated(Ctx))
2035 11: return;
2036 :
2037 14: DD.Triggered = true;
2038 : Diag(DD.Loc, diag::warn_deprecated)
2039 14: << DD.DeprecationData.Decl->getDeclName();
2040 : }
2041 :
2042 73: void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) {
2043 : // Delay if we're currently parsing a declaration.
25: branch 0 taken
48: branch 1 taken
2044 73: if (ParsingDeclDepth) {
2045 25: DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D));
2046 25: return;
2047 : }
2048 :
2049 : // Otherwise, don't warn if our current context is deprecated.
11: branch 2 taken
37: branch 3 taken
2050 48: if (isDeclDeprecated(cast<Decl>(CurContext)))
2051 11: return;
2052 :
2053 37: Diag(Loc, diag::warn_deprecated) << D->getDeclName();
2054 : }
Generated: 2010-02-10 01:31 by zcov