def GlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage()}]>;
+// FIXME: this hack is needed because DeclNodes.td defines the base Decl node
+// type to be a class, not a definition. This makes it impossible to create an
+// attribute subject which accepts a Decl. Normally, this is not a problem,
+// because the attribute can have no Subjects clause to accomplish this. But in
+// the case of a SubsetSubject, there's no way to express it without this hack.
+def DeclBase : AttrSubject;
+def FunctionLike : SubsetSubject<DeclBase,
+ [{S->getFunctionType(false) != NULL}]>;
+
+def HasFunctionProto : SubsetSubject<DeclBase,
+ [{(S->getFunctionType(true) != NULL &&
+ isa<FunctionProtoType>(S->getFunctionType())) ||
+ isa<ObjCMethodDecl>(S) ||
+ isa<BlockDecl>(S)}]>;
+
// A single argument to an attribute
class Argument<string name, bit optional> {
string Name = name;
let Spellings = [GNU<"launch_bounds">];
let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>];
let LangOpts = [CUDA];
+ let Subjects = SubjectList<[ObjCMethod, FunctionLike], WarnDiag,
+ "ExpectedFunctionOrMethod">;
// An AST node is created for this attribute, but is not used by other parts
// of the compiler. However, this node needs to exist in the AST because
// non-LLVM backends may be relying on the attribute's presence.
let Spellings = [GNU<"format">, CXX11<"gnu", "format">];
let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">,
IntArgument<"FirstArg">];
+ let Subjects = SubjectList<[ObjCMethod, Block, FunctionLike,
+ HasFunctionProto], WarnDiag, "ExpectedFunction">;
}
def FormatArg : InheritableAttr {
let Spellings = [GNU<"format_arg">, CXX11<"gnu", "format_arg">];
let Args = [IntArgument<"FormatIdx">];
+ let Subjects = SubjectList<[ObjCMethod, FunctionLike, HasFunctionProto],
+ WarnDiag, "ExpectedFunction">;
}
def GNUInline : InheritableAttr {
def NonNull : InheritableAttr {
let Spellings = [GNU<"nonnull">, CXX11<"gnu", "nonnull">];
+ let Subjects = SubjectList<[ObjCMethod, FunctionLike, HasFunctionProto],
+ WarnDiag, "ExpectedFunction">;
let Args = [VariadicUnsignedArgument<"Args">];
let AdditionalMembers =
[{bool isNonNull(unsigned idx) const {
}
}];
let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">];
+ let Subjects = SubjectList<[FunctionLike, HasFunctionProto], WarnDiag,
+ "ExpectedFunction">;
}
def Packed : InheritableAttr {
def Unused : InheritableAttr {
let Spellings = [GNU<"unused">, CXX11<"gnu", "unused">];
+ let Subjects = SubjectList<[Var, ObjCIvar, Type, Label, Field, ObjCMethod,
+ FunctionLike], WarnDiag,
+ "ExpectedVariableFunctionOrLabel">;
}
def Used : InheritableAttr {
let Spellings = [GNU<"warn_unused_result">,
CXX11<"clang", "warn_unused_result">,
CXX11<"gnu", "warn_unused_result">];
+ let Subjects = SubjectList<[ObjCMethod, CXXRecord, FunctionLike], WarnDiag,
+ "ExpectedFunctionMethodOrClass">;
}
def Weak : InheritableAttr {
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(const Decl *D,
- bool blocksToo = true) {
- QualType Ty;
- if (const ValueDecl *decl = dyn_cast<ValueDecl>(D))
- Ty = decl->getType();
- else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(D))
- Ty = decl->getUnderlyingType();
- else
- return 0;
-
- if (Ty->isFunctionPointerType())
- Ty = Ty->getAs<PointerType>()->getPointeeType();
- else if (blocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
-
- return Ty->getAs<FunctionType>();
-}
-
-// FIXME: We should provide an abstraction around a method or function
-// to provide the following bits of information.
-
-/// isFunction - Return true if the given decl has function
-/// type (function or function-typed variable).
-static bool isFunction(const Decl *D) {
- return getFunctionType(D, false) != NULL;
-}
-
/// isFunctionOrMethod - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method.
static bool isFunctionOrMethod(const Decl *D) {
- return isFunction(D) || isa<ObjCMethodDecl>(D);
-}
-
-/// isFunctionOrMethodOrBlock - Return true if the given decl has function
-/// type (function or function-typed variable) or an Objective-C
-/// method or a block.
-static bool isFunctionOrMethodOrBlock(const Decl *D) {
- if (isFunctionOrMethod(D))
- return true;
- // check for block is more involved.
- if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
- QualType Ty = V->getType();
- return Ty->isBlockPointerType();
- }
- return isa<BlockDecl>(D);
+ return (D->getFunctionType() != NULL) || isa<ObjCMethodDecl>(D);
}
/// Return true if the given decl has a declarator that should have
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
static bool hasFunctionProto(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D))
+ if (const FunctionType *FnTy = D->getFunctionType())
return isa<FunctionProtoType>(FnTy);
- else {
- assert(isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D));
- return true;
- }
+ return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
}
/// getFunctionOrMethodNumArgs - Return number of function or method
/// arguments. It is an error to call this on a K&R function (use
/// hasFunctionProto first).
static unsigned getFunctionOrMethodNumArgs(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D))
+ if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionProtoType>(FnTy)->getNumArgs();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getNumParams();
}
static QualType getFunctionOrMethodArgType(const Decl *D, unsigned Idx) {
- if (const FunctionType *FnTy = getFunctionType(D))
+ if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getParamDecl(Idx)->getType();
}
static QualType getFunctionOrMethodResultType(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D))
+ if (const FunctionType *FnTy = D->getFunctionType())
return cast<FunctionProtoType>(FnTy)->getResultType();
return cast<ObjCMethodDecl>(D)->getResultType();
}
static bool isFunctionOrMethodVariadic(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D)) {
+ if (const FunctionType *FnTy = D->getFunctionType()) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
}
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // GCC ignores the nonnull attribute on K&R style function prototypes, so we
- // ignore it as well
- if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
SmallVector<unsigned, 8> NonNullArgs;
for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
Expr *Ex = Attr.getArgAsExpr(i);
break;
}
- if (!isFunction(D) || !hasFunctionProto(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL.getName() << ExpectedFunction;
- return;
- }
-
IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident;
// Normalize the argument, __foo__ becomes foo.
Attr.getAttributeSpellingListIndex()));
}
-static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
- !isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedVariableFunctionOrLabel;
- return;
- }
-
- D->addAttr(::new (S.Context)
- UnusedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage()) {
} else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(D)
+ const FunctionType *FT = Ty->isFunctionPointerType()
+ ? D->getFunctionType()
: Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
}
static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionMethodOrClass;
- return;
- }
-
- if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) {
+ if (D->getFunctionType() && D->getFunctionType()->getResultType()->isVoidType()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
<< Attr.getName() << 0;
return;
/// Handle __attribute__((format_arg((idx)))) attribute based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
Expr *IdxExpr = Attr.getArgAsExpr(0);
uint64_t ArgIdx;
if (!checkFunctionOrMethodArgumentIndex(S, D, Attr, 1, IdxExpr, ArgIdx))
return;
}
- if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
return;
}
- if (!isFunctionOrMethod(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
uint32_t MaxThreads, MinBlocks = 0;
if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1))
return;
break;
case AttributeList::AT_ObjCRequiresPropertyDefs:
handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); break;
- case AttributeList::AT_Unused: handleUnusedAttr (S, D, Attr); break;
+ case AttributeList::AT_Unused:
+ handleSimpleAttribute<UnusedAttr>(S, D, Attr); break;
case AttributeList::AT_ReturnsTwice:
handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); break;
case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;