r199387 - Factored some function-like type reasoning out of SemaDeclAttr and onto Decl itself. This allows for more declarative subjects in attribute tablegen where the attribute appertains to something function-like, but not strictly a FunctionDecl.
Aaron Ballman
aaron at aaronballman.com
Thu Jan 16 05:55:42 PST 2014
Author: aaronballman
Date: Thu Jan 16 07:55:42 2014
New Revision: 199387
URL: http://llvm.org/viewvc/llvm-project?rev=199387&view=rev
Log:
Factored some function-like type reasoning out of SemaDeclAttr and onto Decl itself. This allows for more declarative subjects in attribute tablegen where the attribute appertains to something function-like, but not strictly a FunctionDecl.
Modified:
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=199387&r1=199386&r2=199387&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Jan 16 07:55:42 2014
@@ -32,6 +32,7 @@ class DeclarationName;
class DependentDiagnostic;
class EnumDecl;
class FunctionDecl;
+class FunctionType;
class LinkageComputer;
class LinkageSpecDecl;
class Module;
@@ -943,6 +944,11 @@ public:
void dumpColor() const;
void dump(raw_ostream &Out) const;
+ /// \brief Looks through the Decl's underlying type to extract a FunctionType
+ /// when possible. Will return null if the type underlying the Decl does not
+ /// have a FunctionType.
+ const FunctionType *getFunctionType(bool BlocksToo = true) const;
+
private:
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=199387&r1=199386&r2=199387&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jan 16 07:55:42 2014
@@ -56,6 +56,21 @@ def SharedVar : SubsetSubject<Var,
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;
@@ -426,6 +441,8 @@ def CUDALaunchBounds : InheritableAttr {
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.
@@ -536,11 +553,15 @@ def Format : InheritableAttr {
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 {
@@ -656,6 +677,8 @@ def NoMips16 : InheritableAttr, TargetSp
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 {
@@ -804,6 +827,8 @@ def Ownership : InheritableAttr {
}
}];
let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">];
+ let Subjects = SubjectList<[FunctionLike, HasFunctionProto], WarnDiag,
+ "ExpectedFunction">;
}
def Packed : InheritableAttr {
@@ -930,6 +955,9 @@ def ObjCRequiresPropertyDefs : Inheritab
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 {
@@ -985,6 +1013,8 @@ def WarnUnusedResult : 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 {
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=199387&r1=199386&r2=199387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Thu Jan 16 07:55:42 2014
@@ -701,6 +701,24 @@ bool Decl::AccessDeclContextSanity() con
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }
+const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
+ QualType Ty;
+ if (const ValueDecl *D = dyn_cast<ValueDecl>(this))
+ Ty = D->getType();
+ else if (const TypedefNameDecl *D = dyn_cast<TypedefNameDecl>(this))
+ Ty = D->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>();
+}
+
+
/// Starting at a given context (a Decl or DeclContext), look for a
/// code context that is not a closure (a lambda, block, etc.).
template <class T> static Decl *getNonClosureContext(T *D) {
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=199387&r1=199386&r2=199387&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jan 16 07:55:42 2014
@@ -43,52 +43,11 @@ namespace AttributeLangSupport {
// 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
@@ -103,19 +62,16 @@ static bool hasDeclarator(const Decl *D)
/// 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();
@@ -123,7 +79,7 @@ static unsigned getFunctionOrMethodNumAr
}
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();
@@ -132,13 +88,13 @@ static QualType getFunctionOrMethodArgTy
}
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))
@@ -1201,14 +1157,6 @@ static void possibleTransparentUnionPoin
}
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);
@@ -1306,12 +1254,6 @@ static void handleOwnershipAttr(Sema &S,
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.
@@ -1636,19 +1578,6 @@ static void handleDependencyAttr(Sema &S
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()) {
@@ -2185,7 +2114,8 @@ static void handleSentinelAttr(Sema &S,
} 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;
@@ -2208,13 +2138,7 @@ static void handleSentinelAttr(Sema &S,
}
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;
@@ -2408,12 +2332,6 @@ static void handleCleanupAttr(Sema &S, D
/// 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))
@@ -2558,12 +2476,6 @@ static void handleFormatAttr(Sema &S, De
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);
@@ -3295,12 +3207,6 @@ static void handleLaunchBoundsAttr(Sema
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;
@@ -4120,7 +4026,8 @@ static void ProcessDeclAttribute(Sema &S
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;
Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=199387&r1=199386&r2=199387&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Thu Jan 16 07:55:42 2014
@@ -2061,6 +2061,12 @@ static std::string CalculateDiagnostic(c
return "";
}
+static std::string GetSubjectWithSuffix(const Record *R) {
+ std::string B = R->getName();
+ if (B == "DeclBase")
+ return "Decl";
+ return B + "Decl";
+}
static std::string GenerateCustomAppertainsTo(const Record &Subject,
raw_ostream &OS) {
std::string FnName = "is" + Subject.getName();
@@ -2082,9 +2088,9 @@ static std::string GenerateCustomApperta
}
OS << "static bool " << FnName << "(const Decl *D) {\n";
- OS << " const " << Base->getName() << "Decl *S = dyn_cast<";
- OS << Base->getName();
- OS << "Decl>(D);\n";
+ OS << " const " << GetSubjectWithSuffix(Base) << " *S = dyn_cast<";
+ OS << GetSubjectWithSuffix(Base);
+ OS << ">(D);\n";
OS << " return S && " << Subject.getValueAsString("CheckCode") << ";\n";
OS << "}\n\n";
@@ -2126,7 +2132,7 @@ static std::string GenerateAppertainsTo(
if ((*I)->isSubClassOf("SubsetSubject")) {
SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)";
} else {
- SS << "!isa<" << (*I)->getName() << "Decl>(D)";
+ SS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
}
if (I + 1 != E)
More information about the cfe-commits
mailing list