[{!S->isBitField()}]>;
// A single argument to an attribute
-class Argument<string name> {
+class Argument<string name, bit optional> {
string Name = name;
+ bit Optional = optional;
}
-class BoolArgument<string name> : Argument<name>;
-class IdentifierArgument<string name> : Argument<name>;
-class IntArgument<string name> : Argument<name>;
-class StringArgument<string name> : Argument<name>;
-class ExprArgument<string name> : Argument<name>;
-class FunctionArgument<string name> : Argument<name>;
-class TypeArgument<string name> : Argument<name>;
-class UnsignedArgument<string name> : Argument<name>;
-class SourceLocArgument<string name> : Argument<name>;
-class VariadicUnsignedArgument<string name> : Argument<name>;
-class VariadicExprArgument<string name> : Argument<name>;
+class BoolArgument<string name, bit opt = 0> : Argument<name, opt>;
+class IdentifierArgument<string name, bit opt = 0> : Argument<name, opt>;
+class IntArgument<string name, bit opt = 0> : Argument<name, opt>;
+class StringArgument<string name, bit opt = 0> : Argument<name, opt>;
+class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
+class FunctionArgument<string name, bit opt = 0> : Argument<name, opt>;
+class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
+class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
+class SourceLocArgument<string name, bit opt = 0> : Argument<name, opt>;
+class VariadicUnsignedArgument<string name> : Argument<name, 1>;
+class VariadicExprArgument<string name> : Argument<name, 1>;
// A version of the form major.minor[.subminor].
-class VersionArgument<string name> : Argument<name>;
+class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
// This one's a doozy, so it gets its own special type
// It can be an unsigned integer, or a type. Either can
// be dependent.
-class AlignedArgument<string name> : Argument<name>;
+class AlignedArgument<string name, bit opt = 0> : Argument<name, opt>;
// An integer argument with a default value
-class DefaultIntArgument<string name, int default> : IntArgument<name> {
+class DefaultIntArgument<string name, int default> : IntArgument<name, 1> {
int Default = default;
}
// This argument is more complex, it includes the enumerator type name,
// a list of strings to accept, and a list of enumerators to map them to.
class EnumArgument<string name, string type, list<string> values,
- list<string> enums> : Argument<name> {
+ list<string> enums, bit opt = 0> : Argument<name, opt> {
string Type = type;
list<string> Values = values;
list<string> Enums = enums;
bit Ignored = 0;
// Set to true if each of the spellings is a distinct attribute.
bit DistinctSpellings = 0;
+ // Set to true if the attribute's parsing does not match its semantic
+ // content. Eg) It parses 3 args, but semantically takes 4 args. Opts out of
+ // common attribute error checking.
+ bit HasCustomParsing = 0;
// Any additional text that should be included verbatim in the class.
code AdditionalMembers = [{}];
}
let Spellings = [GNU<"aligned">, Declspec<"align">, CXX11<"gnu", "aligned">,
Keyword<"alignas">, Keyword<"_Alignas">];
let Subjects = [NonBitField, NormalVar, Tag];
- let Args = [AlignedArgument<"Alignment">];
+ let Args = [AlignedArgument<"Alignment", 1>];
let Accessors = [Accessor<"isGNU", [GNU<"aligned">, CXX11<"gnu","aligned">]>,
Accessor<"isC11", [Keyword<"_Alignas">]>,
Accessor<"isAlignas", [Keyword<"alignas">,
.Case("macosx", "OS X")
.Default(llvm::StringRef());
} }];
+ let HasCustomParsing = 1;
}
def Blocks : InheritableAttr {
def Constructor : InheritableAttr {
let Spellings = [GNU<"constructor">, CXX11<"gnu", "constructor">];
- let Args = [IntArgument<"Priority">];
+ let Args = [IntArgument<"Priority", 1>];
}
def CUDAConstant : InheritableAttr {
def Deprecated : InheritableAttr {
let Spellings = [GNU<"deprecated">, CXX11<"gnu", "deprecated">];
- let Args = [StringArgument<"Message">];
+ let Args = [StringArgument<"Message", 1>];
}
def Destructor : InheritableAttr {
let Spellings = [GNU<"destructor">, CXX11<"gnu", "destructor">];
- let Args = [IntArgument<"Priority">];
+ let Args = [IntArgument<"Priority", 1>];
}
def ExtVectorType : Attr {
def IBOutletCollection : InheritableAttr {
let Spellings = [GNU<"iboutletcollection">];
- let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">];
+ let Args = [TypeArgument<"Interface", 1>, SourceLocArgument<"InterfaceLoc">];
}
def Malloc : InheritableAttr {
def NSBridged : InheritableAttr {
let Spellings = [GNU<"ns_bridged">];
let Subjects = [Record];
- let Args = [IdentifierArgument<"BridgedType">];
+ let Args = [IdentifierArgument<"BridgedType", 1>];
}
def NSReturnsRetained : InheritableAttr {
def Unavailable : InheritableAttr {
let Spellings = [GNU<"unavailable">];
- let Args = [StringArgument<"Message">];
+ let Args = [StringArgument<"Message", 1>];
}
def ArcWeakrefUnavailable : InheritableAttr {
def VecTypeHint : InheritableAttr {
let Spellings = [GNU<"vec_type_hint">];
let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">];
+ let HasCustomParsing = 1;
}
def Visibility : InheritableAttr {
def WeakRef : InheritableAttr {
let Spellings = [GNU<"weakref">, CXX11<"gnu", "weakref">];
+ // A WeakRef that has an argument is treated as being an AliasAttr
+ let Args = [StringArgument<"Aliasee", 1>];
}
def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr {
UnsignedArgument<"TypeTagIdx">,
BoolArgument<"IsPointer">];
let Subjects = [Function];
+ let HasCustomParsing = 1;
}
def TypeTagForDatatype : InheritableAttr {
BoolArgument<"LayoutCompatible">,
BoolArgument<"MustBeNull">];
let Subjects = [Var];
+ let HasCustomParsing = 1;
}
// Microsoft-related attributes
static bool checkGuardedVarAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return false;
-
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
Expr* &Arg) {
- if (!checkAttributeNumArgs(S, Attr, 1))
- return false;
-
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
static bool checkLockableAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return false;
-
// FIXME: Lockable structs for C code.
if (!isa<RecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
<< Attr.getName() << ThreadExpectedFunctionOrMethod;
static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
static void handleNoSanitizeMemory(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
static void handleNoSanitizeThread(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
static void handleLockReturnedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
<< Attr.getName() << ThreadExpectedFunctionOrMethod;
}
static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
ConsumableAttr::ConsumedState DefaultState;
if (Attr.isArgIdent(0)) {
}
static void handleConsumesAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
if (!isa<CXXMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
Attr.getName() << ExpectedMethod;
static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
if (!isa<CXXMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
Attr.getName() << ExpectedMethod;
static void handleTestsConsumedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
if (!isa<CXXMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
Attr.getName() << ExpectedMethod;
static void handleTestsUnconsumedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0)) return;
-
if (!isa<CXXMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
Attr.getName() << ExpectedMethod;
static void handleReturnTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 1)) return;
-
ReturnTypestateAttr::ConsumedState ReturnState;
if (Attr.isArgIdent(0)) {
}
static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
}
static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
// The IBAction attributes only apply to instance methods.
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
if (MD->isInstanceMethod()) {
}
static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!checkIBOutletCommon(S, D, Attr))
return;
}
static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
StringLiteral *Str = 0;
if (Attr.isArgExpr(0))
Str = dyn_cast<StringLiteral>(Attr.getArgAsExpr(0)->IgnoreParenCasts());
}
static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
}
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
}
static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
}
static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
static void handleTLSModelAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
Expr *Arg = Attr.getArgAsExpr(0);
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
}
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getResultType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
}
static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
MayAliasAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
// The checking path for 'noreturn' and 'analyzer_noreturn' are different
// because 'analyzer_noreturn' does not impact the type.
-
- if(!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (VD == 0 || (!VD->getType()->isBlockPointerType()
}
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
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)
static void handleReturnsTwiceAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
}
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
}
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
ObjCRootClassAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
}
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
}
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
// Check that the argument is a string literal.
StringLiteral *Str = 0;
if (Attr.isArgExpr(0))
return;
}
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
IdentifierLoc *IL = Attr.getArgAsIdent(0);
StringRef param = IL->Ident->getName();
static void handleObjCExceptionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
if (OCI == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (!T->isCARCBridgableType()) {
static void
handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
return;
<< Attr.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
-
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
BlocksAttr::BlockType type;
}
static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context));
else
}
static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrClass;
}
static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
if (isa<CXXRecordDecl>(D)) {
D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
}
static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
// weak_import only applies to variable & function declarations.
bool isDef = false;
if (!D->canBeWeakImported(isDef)) {
// Handles reqd_work_group_size and work_group_size_hint.
static void handleWorkGroupSize(Sema &S, Decl *D,
const AttributeList &Attr) {
- assert(Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
- || Attr.getKind() == AttributeList::AT_WorkGroupSizeHint);
-
- // Attribute has 3 arguments.
- if (!checkAttributeNumArgs(S, Attr, 3)) return;
-
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
Expr *E = Attr.getArgAsExpr(i);
}
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Attribute has no arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
// Make sure that there is a string literal as the sections's single
// argument.
Expr *ArgExpr = Attr.getArgAsExpr(0);
static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
}
static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
}
static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
D->addAttr(::new (S.Context)
PureAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
}
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD || !VD->hasLocalStorage()) {
/// 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 (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
return;
}
- if (!checkAttributeNumArgs(S, Attr, 1)) {
- Attr.setInvalid();
- return;
- }
Expr *priorityExpr = Attr.getArgAsExpr(0);
llvm::APSInt priority(32);
<< Attr.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
-
- if (!checkAttributeNumArgs(S, Attr, 3))
- return;
if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
static void handleTransparentUnionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
// Try to find the underlying union declaration.
RecordDecl *RD = 0;
TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
}
static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
Expr *ArgExpr = Attr.getArgAsExpr(0);
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
return;
}
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident;
StringRef Str = Name->getName();
}
static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->hasGlobalStorage())
S.Diag(Attr.getLoc(),
}
static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
-
if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunction;
static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CUDA) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 0))
- return;
-
FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland))
return;
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
Expr *Arg = Attr.getArgAsExpr(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (!Str || !Str->isAscii()) {
Attr.getAttributeSpellingListIndex()));
}
+/// Handles semantic checking for features that are common to all attributes,
+/// such as checking whether a parameter was properly specified, or the correct
+/// number of arguments were passed, etc.
+static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
+ const AttributeList &Attr) {
+ // Several attributes carry different semantics than the parsing requires, so
+ // those are opted out of the common handling.
+ //
+ // We also bail on unknown and ignored attributes because those are handled
+ // as part of the target-specific handling logic.
+ if (Attr.hasCustomParsing() ||
+ Attr.getKind() == AttributeList::UnknownAttribute ||
+ Attr.getKind() == AttributeList::IgnoredAttribute)
+ return false;
+
+ // If there are no optional arguments, then checking for the argument count
+ // is trivial.
+ if (Attr.getMinArgs() == Attr.getMaxArgs() &&
+ !checkAttributeNumArgs(S, Attr, Attr.getMinArgs()))
+ return true;
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
return;
+ if (handleCommonAttributeFeatures(S, scope, D, Attr))
+ return;
+
switch (Attr.getKind()) {
case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
class Argument {
std::string lowerName, upperName;
StringRef attrName;
+ bool isOpt;
public:
Argument(Record &Arg, StringRef Attr)
: lowerName(Arg.getValueAsString("Name")), upperName(lowerName),
- attrName(Attr) {
+ attrName(Attr), isOpt(false) {
if (!lowerName.empty()) {
lowerName[0] = std::tolower(lowerName[0]);
upperName[0] = std::toupper(upperName[0]);
StringRef getUpperName() const { return upperName; }
StringRef getAttrName() const { return attrName; }
+ bool isOptional() const { return isOpt; }
+ void setOptional(bool set) { isOpt = set; }
+
// These functions print the argument contents formatted in different ways.
virtual void writeAccessors(raw_ostream &OS) const = 0;
virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
virtual void writeTemplateInstantiation(raw_ostream &OS) const {}
virtual void writeCtorBody(raw_ostream &OS) const {}
virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
+ virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0;
virtual void writeCtorParameters(raw_ostream &OS) const = 0;
virtual void writeDeclarations(raw_ostream &OS) const = 0;
virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "()";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << type << " " << getUpperName();
}
<< getLowerName() << "(new (Ctx, 1) char[" << getLowerName()
<< "Length])";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "Length(0)," << getLowerName() << "(0)";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << "llvm::StringRef " << getUpperName();
}
void writeCtorInitializers(raw_ostream &OS) const {
OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << "is" << getLowerName() << "Expr(false)";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
}
<< getLowerName() << "(new (Ctx, 16) " << getType() << "["
<< getLowerName() << "Size])";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "Size(0), " << getLowerName() << "(0)";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << getType() << " *" << getUpperName() << ", unsigned "
<< getUpperName() << "Size";
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "(" << type << "(0))";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << type << " " << getUpperName();
}
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
+ void writeCtorDefaultInitializers(raw_ostream &OS) const {
+ OS << getLowerName() << "()";
+ }
void writeCtorParameters(raw_ostream &OS) const {
OS << "VersionTuple " << getUpperName();
}
break;
}
}
+
+ if (Ptr && Arg.getValueAsBit("Optional"))
+ Ptr->setOptional(true);
+
return Ptr;
}
OS << "\n public:\n";
OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+ bool HasOpt = false;
for (ai = Args.begin(); ai != ae; ++ai) {
OS << " , ";
(*ai)->writeCtorParameters(OS);
OS << "\n";
+ if ((*ai)->isOptional())
+ HasOpt = true;
}
OS << " , ";
}
OS << " }\n\n";
+ // If there are optional arguments, write out a constructor that elides the
+ // optional arguments as well.
+ if (HasOpt) {
+ OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ if (!(*ai)->isOptional()) {
+ OS << " , ";
+ (*ai)->writeCtorParameters(OS);
+ OS << "\n";
+ }
+ }
+
+ OS << " , ";
+ OS << "unsigned SI = 0\n";
+
+ OS << " )\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ OS << " , ";
+ (*ai)->writeCtorDefaultInitializers(OS);
+ OS << "\n";
+ }
+
+ OS << " {\n";
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ if (!(*ai)->isOptional()) {
+ (*ai)->writeCtorBody(OS);
+ OS << "\n";
+ }
+ }
+ OS << " }\n\n";
+ }
+
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
OS << " virtual void printPretty(raw_ostream &OS,\n"
<< " const PrintingPolicy &Policy) const;\n";
<< "} // end namespace clang\n";
}
-// Emits the list of parsed attributes.
-void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+typedef std::vector<std::pair<std::string, Record *> > ParsedAttrMap;
- OS << "#ifndef PARSED_ATTR\n";
- OS << "#define PARSED_ATTR(NAME) NAME\n";
- OS << "#endif\n\n";
-
+static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) {
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
+ ParsedAttrMap R;
for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
I != E; ++I) {
Record &Attr = **I;
std::string AttrName = (*I)->getValueAsString("Name");
StringRef Spelling = NormalizeAttrName(AttrName);
-
- OS << "PARSED_ATTR(" << Spelling << ")\n";
+ R.push_back(std::make_pair(Spelling.str(), &Attr));
}
} else {
StringRef AttrName = Attr.getName();
AttrName = NormalizeAttrName(AttrName);
- OS << "PARSED_ATTR(" << AttrName << ")\n";
+ R.push_back(std::make_pair(AttrName.str(), *I));
}
}
}
+ return R;
+}
+
+// Emits the list of parsed attributes.
+void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+
+ OS << "#ifndef PARSED_ATTR\n";
+ OS << "#define PARSED_ATTR(NAME) NAME\n";
+ OS << "#endif\n\n";
+
+ ParsedAttrMap Names = getParsedAttrList(Records);
+ for (ParsedAttrMap::iterator I = Names.begin(), E = Names.end(); I != E;
+ ++I) {
+ OS << "PARSED_ATTR(" << I->first << ")\n";
+ }
+}
+
+static void emitArgInfo(const Record &R, raw_ostream &OS) {
+ // This function will count the number of arguments specified for the
+ // attribute and emit the number of required arguments followed by the
+ // number of optional arguments.
+ std::vector<Record *> Args = R.getValueAsListOfDefs("Args");
+ unsigned ArgCount = 0, OptCount = 0;
+ for (std::vector<Record *>::const_iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
+ const Record &Arg = **I;
+ Arg.getValueAsBit("Optional") ? ++OptCount : ++ArgCount;
+ }
+ OS << ArgCount << ", " << OptCount;
+}
+
+/// Emits the parsed attribute helpers
+void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Parsed attribute helpers", OS);
+
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+
+ OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
+ for (ParsedAttrMap::iterator I = Attrs.begin(), E = Attrs.end(); I != E;
+ ++I) {
+ // We need to generate struct instances based off ParsedAttrInfo from
+ // AttributeList.cpp.
+ OS << " { ";
+ emitArgInfo(*I->second, OS);
+ OS << ", " << I->second->getValueAsBit("HasCustomParsing");
+ OS << " }";
+
+ if (I + 1 != E)
+ OS << ",";
+
+ OS << " // AT_" << I->first << "\n";
+ }
+ OS << "};\n\n";
}
// Emits the kind list of parsed attributes