mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-09 01:29:52 +00:00
Revert r326602, it caused PR36620.
llvm-svn: 326862
This commit is contained in:
parent
204ade4102
commit
bbf648253d
@ -195,120 +195,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// A single parameter index whose accessors require each use to make explicit
|
||||
/// the parameter index encoding needed.
|
||||
class ParamIdx {
|
||||
// Idx is exposed only via accessors that specify specific encodings.
|
||||
unsigned Idx : 30;
|
||||
unsigned HasThis : 1;
|
||||
unsigned IsValid : 1;
|
||||
|
||||
void assertComparable(const ParamIdx &I) const {
|
||||
assert(isValid() && I.isValid() &&
|
||||
"ParamIdx must be valid to be compared");
|
||||
// It's possible to compare indices from separate functions, but so far
|
||||
// it's not proven useful. Moreover, it might be confusing because a
|
||||
// comparison on the results of getASTIndex might be inconsistent with a
|
||||
// comparison on the ParamIdx objects themselves.
|
||||
assert(HasThis == I.HasThis &&
|
||||
"ParamIdx must be for the same function to be compared");
|
||||
}
|
||||
|
||||
public:
|
||||
/// Construct an invalid parameter index (\c isValid returns false and
|
||||
/// accessors fail an assert).
|
||||
ParamIdx() : Idx(0), HasThis(false), IsValid(false) {}
|
||||
|
||||
/// \param Idx is the parameter index as it is normally specified in
|
||||
/// attributes in the source: one-origin including any C++ implicit this
|
||||
/// parameter.
|
||||
///
|
||||
/// \param D is the declaration containing the parameters. It is used to
|
||||
/// determine if there is a C++ implicit this parameter.
|
||||
ParamIdx(unsigned Idx, const Decl *D)
|
||||
: Idx(Idx), HasThis(false), IsValid(true) {
|
||||
if (const auto *FD = dyn_cast<FunctionDecl>(D))
|
||||
HasThis = FD->isCXXInstanceMember();
|
||||
}
|
||||
|
||||
/// \param Idx is the parameter index as it is normally specified in
|
||||
/// attributes in the source: one-origin including any C++ implicit this
|
||||
/// parameter.
|
||||
///
|
||||
/// \param HasThis specifies whether the function has a C++ implicit this
|
||||
/// parameter.
|
||||
ParamIdx(unsigned Idx, bool HasThis)
|
||||
: Idx(Idx), HasThis(HasThis), IsValid(true) {}
|
||||
|
||||
/// Is this parameter index valid?
|
||||
bool isValid() const { return IsValid; }
|
||||
|
||||
/// Is there a C++ implicit this parameter?
|
||||
bool hasThis() const {
|
||||
assert(isValid() && "ParamIdx must be valid");
|
||||
return HasThis;
|
||||
}
|
||||
|
||||
/// Get the parameter index as it would normally be encoded for attributes at
|
||||
/// the source level of representation: one-origin including any C++ implicit
|
||||
/// this parameter.
|
||||
///
|
||||
/// This encoding thus makes sense for diagnostics, pretty printing, and
|
||||
/// constructing new attributes from a source-like specification.
|
||||
unsigned getSourceIndex() const {
|
||||
assert(isValid() && "ParamIdx must be valid");
|
||||
return Idx;
|
||||
}
|
||||
|
||||
/// Get the parameter index as it would normally be encoded at the AST level
|
||||
/// of representation: zero-origin not including any C++ implicit this
|
||||
/// parameter.
|
||||
///
|
||||
/// This is the encoding primarily used in Sema. However, in diagnostics,
|
||||
/// Sema uses \c getSourceIndex instead.
|
||||
unsigned getASTIndex() const {
|
||||
assert(isValid() && "ParamIdx must be valid");
|
||||
assert(Idx >= 1 + HasThis &&
|
||||
"stored index must be base-1 and not specify C++ implicit this");
|
||||
return Idx - 1 - HasThis;
|
||||
}
|
||||
|
||||
/// Get the parameter index as it would normally be encoded at the LLVM level
|
||||
/// of representation: zero-origin including any C++ implicit this parameter.
|
||||
///
|
||||
/// This is the encoding primarily used in CodeGen.
|
||||
unsigned getLLVMIndex() const {
|
||||
assert(isValid() && "ParamIdx must be valid");
|
||||
assert(Idx >= 1 && "stored index must be base-1");
|
||||
return Idx - 1;
|
||||
}
|
||||
|
||||
bool operator==(const ParamIdx &I) const {
|
||||
assertComparable(I);
|
||||
return Idx == I.Idx;
|
||||
}
|
||||
bool operator!=(const ParamIdx &I) const {
|
||||
assertComparable(I);
|
||||
return Idx != I.Idx;
|
||||
}
|
||||
bool operator<(const ParamIdx &I) const {
|
||||
assertComparable(I);
|
||||
return Idx < I.Idx;
|
||||
}
|
||||
bool operator>(const ParamIdx &I) const {
|
||||
assertComparable(I);
|
||||
return Idx > I.Idx;
|
||||
}
|
||||
bool operator<=(const ParamIdx &I) const {
|
||||
assertComparable(I);
|
||||
return Idx <= I.Idx;
|
||||
}
|
||||
bool operator>=(const ParamIdx &I) const {
|
||||
assertComparable(I);
|
||||
return Idx >= I.Idx;
|
||||
}
|
||||
};
|
||||
|
||||
#include "clang/AST/Attrs.inc"
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
|
@ -169,12 +169,6 @@ class VariadicUnsignedArgument<string name> : Argument<name, 1>;
|
||||
class VariadicExprArgument<string name> : Argument<name, 1>;
|
||||
class VariadicStringArgument<string name> : Argument<name, 1>;
|
||||
|
||||
// Like VariadicUnsignedArgument except values are ParamIdx.
|
||||
class VariadicParamIdxArgument<string name> : Argument<name, 1>;
|
||||
|
||||
// Like VariadicParamIdxArgument but for a single function parameter index.
|
||||
class ParamIdxArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
|
||||
// A version of the form major.minor[.subminor].
|
||||
class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
|
||||
@ -620,12 +614,6 @@ def XRayInstrument : InheritableAttr {
|
||||
def XRayLogArgs : InheritableAttr {
|
||||
let Spellings = [Clang<"xray_log_args">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod]>;
|
||||
// This argument is a count not an index, so it has the same encoding (base
|
||||
// 1 including C++ implicit this parameter) at the source and LLVM levels of
|
||||
// representation, so ParamIdxArgument is inappropriate. It is never used
|
||||
// at the AST level of representation, so it never needs to be adjusted not
|
||||
// to include any C++ implicit this parameter. Thus, we just store it and
|
||||
// use it as an unsigned that never needs adjustment.
|
||||
let Args = [UnsignedArgument<"ArgumentCount">];
|
||||
let Documentation = [XRayDocs];
|
||||
}
|
||||
@ -1033,8 +1021,7 @@ def EmptyBases : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
|
||||
def AllocSize : InheritableAttr {
|
||||
let Spellings = [GCC<"alloc_size">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Args = [ParamIdxArgument<"ElemSizeParam">,
|
||||
ParamIdxArgument<"NumElemsParam", /*opt*/ 1>];
|
||||
let Args = [IntArgument<"ElemSizeParam">, IntArgument<"NumElemsParam", 1>];
|
||||
let TemplateDependent = 1;
|
||||
let Documentation = [AllocSizeDocs];
|
||||
}
|
||||
@ -1121,7 +1108,7 @@ def Format : InheritableAttr {
|
||||
|
||||
def FormatArg : InheritableAttr {
|
||||
let Spellings = [GCC<"format_arg">];
|
||||
let Args = [ParamIdxArgument<"FormatIdx">];
|
||||
let Args = [IntArgument<"FormatIdx">];
|
||||
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto]>;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
@ -1401,16 +1388,16 @@ def NonNull : InheritableParamAttr {
|
||||
let Spellings = [GCC<"nonnull">];
|
||||
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag,
|
||||
"functions, methods, and parameters">;
|
||||
let Args = [VariadicParamIdxArgument<"Args">];
|
||||
let AdditionalMembers = [{
|
||||
bool isNonNull(unsigned IdxAST) const {
|
||||
if (!args_size())
|
||||
let Args = [VariadicUnsignedArgument<"Args">];
|
||||
let AdditionalMembers =
|
||||
[{bool isNonNull(unsigned idx) const {
|
||||
if (!args_size())
|
||||
return true;
|
||||
for (const auto &V : args())
|
||||
if (V == idx)
|
||||
return true;
|
||||
return args_end() != std::find_if(
|
||||
args_begin(), args_end(),
|
||||
[=](const ParamIdx &Idx) { return Idx.getASTIndex() == IdxAST; });
|
||||
}
|
||||
}];
|
||||
return false;
|
||||
} }];
|
||||
// FIXME: We should merge duplicates into a single nonnull attribute.
|
||||
let InheritEvenIfAlreadyPresent = 1;
|
||||
let Documentation = [NonNullDocs];
|
||||
@ -1468,7 +1455,7 @@ def AssumeAligned : InheritableAttr {
|
||||
def AllocAlign : InheritableAttr {
|
||||
let Spellings = [GCC<"alloc_align">];
|
||||
let Subjects = SubjectList<[HasFunctionProto]>;
|
||||
let Args = [ParamIdxArgument<"ParamIndex">];
|
||||
let Args = [IntArgument<"ParamIndex">];
|
||||
let Documentation = [AllocAlignDocs];
|
||||
}
|
||||
|
||||
@ -1677,8 +1664,7 @@ def Ownership : InheritableAttr {
|
||||
Returns;
|
||||
}
|
||||
}];
|
||||
let Args = [IdentifierArgument<"Module">,
|
||||
VariadicParamIdxArgument<"Args">];
|
||||
let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">];
|
||||
let Subjects = SubjectList<[HasFunctionProto]>;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
@ -2504,8 +2490,8 @@ def ArgumentWithTypeTag : InheritableAttr {
|
||||
Clang<"pointer_with_type_tag">];
|
||||
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
|
||||
let Args = [IdentifierArgument<"ArgumentKind">,
|
||||
ParamIdxArgument<"ArgumentIdx">,
|
||||
ParamIdxArgument<"TypeTagIdx">,
|
||||
UnsignedArgument<"ArgumentIdx">,
|
||||
UnsignedArgument<"TypeTagIdx">,
|
||||
BoolArgument<"IsPointer", /*opt*/0, /*fake*/1>];
|
||||
let Documentation = [ArgumentWithTypeTagDocs, PointerWithTypeTagDocs];
|
||||
}
|
||||
|
@ -5467,8 +5467,9 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
|
||||
llvm::APInt &Result) {
|
||||
const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call);
|
||||
|
||||
assert(AllocSize && AllocSize->elemSizeParam().isValid());
|
||||
unsigned SizeArgNo = AllocSize->elemSizeParam().getASTIndex();
|
||||
// alloc_size args are 1-indexed, 0 means not present.
|
||||
assert(AllocSize && AllocSize->getElemSizeParam() != 0);
|
||||
unsigned SizeArgNo = AllocSize->getElemSizeParam() - 1;
|
||||
unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType());
|
||||
if (Call->getNumArgs() <= SizeArgNo)
|
||||
return false;
|
||||
@ -5486,13 +5487,14 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
|
||||
if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem))
|
||||
return false;
|
||||
|
||||
if (!AllocSize->numElemsParam().isValid()) {
|
||||
if (!AllocSize->getNumElemsParam()) {
|
||||
Result = std::move(SizeOfElem);
|
||||
return true;
|
||||
}
|
||||
|
||||
APSInt NumberOfElems;
|
||||
unsigned NumArgNo = AllocSize->numElemsParam().getASTIndex();
|
||||
// Argument numbers start at 1
|
||||
unsigned NumArgNo = AllocSize->getNumElemsParam() - 1;
|
||||
if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems))
|
||||
return false;
|
||||
|
||||
|
@ -1847,9 +1847,10 @@ void CodeGenModule::ConstructAttributeList(
|
||||
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
|
||||
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
|
||||
Optional<unsigned> NumElemsParam;
|
||||
if (AllocSize->numElemsParam().isValid())
|
||||
NumElemsParam = AllocSize->numElemsParam().getLLVMIndex();
|
||||
FuncAttrs.addAllocSizeAttr(AllocSize->elemSizeParam().getLLVMIndex(),
|
||||
// alloc_size args are base-1, 0 means not present.
|
||||
if (unsigned N = AllocSize->getNumElemsParam())
|
||||
NumElemsParam = N - 1;
|
||||
FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam() - 1,
|
||||
NumElemsParam);
|
||||
}
|
||||
}
|
||||
@ -4392,7 +4393,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
OffsetValue);
|
||||
} else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
|
||||
llvm::Value *ParamVal =
|
||||
CallArgs[AA->paramIndex().getLLVMIndex()].RV.getScalarVal();
|
||||
CallArgs[AA->getParamIndex() - 1].RV.getScalarVal();
|
||||
EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal);
|
||||
}
|
||||
}
|
||||
|
@ -2619,13 +2619,12 @@ static void CheckNonNullArguments(Sema &S,
|
||||
return;
|
||||
}
|
||||
|
||||
for (const ParamIdx &Idx : NonNull->args()) {
|
||||
unsigned IdxAST = Idx.getASTIndex();
|
||||
if (IdxAST >= Args.size())
|
||||
for (unsigned Val : NonNull->args()) {
|
||||
if (Val >= Args.size())
|
||||
continue;
|
||||
if (NonNullArgs.empty())
|
||||
NonNullArgs.resize(Args.size());
|
||||
NonNullArgs.set(IdxAST);
|
||||
NonNullArgs.set(Val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5003,7 +5002,12 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
|
||||
const CallExpr *CE = cast<CallExpr>(E);
|
||||
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
|
||||
if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
|
||||
const Expr *Arg = CE->getArg(FA->formatIdx().getASTIndex());
|
||||
unsigned ArgIndex = FA->getFormatIdx();
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
|
||||
if (MD->isInstance())
|
||||
--ArgIndex;
|
||||
const Expr *Arg = CE->getArg(ArgIndex - 1);
|
||||
|
||||
return checkFormatStringExpr(S, Arg, Args,
|
||||
HasVAListArg, format_idx, firstDataArg,
|
||||
Type, CallType, InFunctionCall,
|
||||
@ -5028,7 +5032,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
|
||||
const auto *ME = cast<ObjCMessageExpr>(E);
|
||||
if (const auto *ND = ME->getMethodDecl()) {
|
||||
if (const auto *FA = ND->getAttr<FormatArgAttr>()) {
|
||||
const Expr *Arg = ME->getArg(FA->formatIdx().getASTIndex());
|
||||
unsigned ArgIndex = FA->getFormatIdx();
|
||||
const Expr *Arg = ME->getArg(ArgIndex - 1);
|
||||
return checkFormatStringExpr(
|
||||
S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
|
||||
CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
|
||||
@ -10081,8 +10086,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
|
||||
return;
|
||||
}
|
||||
|
||||
for (const ParamIdx &ArgNo : NonNull->args()) {
|
||||
if (ArgNo.getASTIndex() == ParamNo) {
|
||||
for (unsigned ArgNo : NonNull->args()) {
|
||||
if (ArgNo == ParamNo) {
|
||||
ComplainAboutNonnullParamOrCall(NonNull);
|
||||
return;
|
||||
}
|
||||
@ -12237,13 +12242,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
|
||||
bool IsPointerAttr = Attr->getIsPointer();
|
||||
|
||||
// Retrieve the argument representing the 'type_tag'.
|
||||
unsigned TypeTagIdxAST = Attr->typeTagIdx().getASTIndex();
|
||||
if (TypeTagIdxAST >= ExprArgs.size()) {
|
||||
if (Attr->getTypeTagIdx() >= ExprArgs.size()) {
|
||||
// Add 1 to display the user's specified value.
|
||||
Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
|
||||
<< 0 << Attr->typeTagIdx().getSourceIndex();
|
||||
<< 0 << Attr->getTypeTagIdx() + 1;
|
||||
return;
|
||||
}
|
||||
const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST];
|
||||
const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()];
|
||||
bool FoundWrongKind;
|
||||
TypeTagData TypeInfo;
|
||||
if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
|
||||
@ -12257,13 +12262,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
|
||||
}
|
||||
|
||||
// Retrieve the argument representing the 'arg_idx'.
|
||||
unsigned ArgumentIdxAST = Attr->argumentIdx().getASTIndex();
|
||||
if (ArgumentIdxAST >= ExprArgs.size()) {
|
||||
if (Attr->getArgumentIdx() >= ExprArgs.size()) {
|
||||
// Add 1 to display the user's specified value.
|
||||
Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
|
||||
<< 1 << Attr->argumentIdx().getSourceIndex();
|
||||
<< 1 << Attr->getArgumentIdx() + 1;
|
||||
return;
|
||||
}
|
||||
const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST];
|
||||
const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()];
|
||||
if (IsPointerAttr) {
|
||||
// Skip implicit cast of pointer to `void *' (as a function argument).
|
||||
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
|
||||
|
@ -13176,7 +13176,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
|
||||
// We already have a __builtin___CFStringMakeConstantString,
|
||||
// but builds that use -fno-constant-cfstrings don't go through that.
|
||||
if (!FD->hasAttr<FormatArgAttr>())
|
||||
FD->addAttr(FormatArgAttr::CreateImplicit(Context, ParamIdx(1, FD),
|
||||
FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1,
|
||||
FD->getLocation()));
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
|
||||
template <typename AttrInfo>
|
||||
static bool checkFunctionOrMethodParameterIndex(
|
||||
Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum,
|
||||
const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) {
|
||||
const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) {
|
||||
assert(isFunctionOrMethodOrBlock(D));
|
||||
|
||||
// In C++ the implicit 'this' function parameter also counts.
|
||||
@ -331,20 +331,21 @@ static bool checkFunctionOrMethodParameterIndex(
|
||||
return false;
|
||||
}
|
||||
|
||||
Idx = ParamIdx(IdxInt.getLimitedValue(UINT_MAX), D);
|
||||
unsigned IdxSource = Idx.getSourceIndex();
|
||||
if (IdxSource < 1 || (!IV && IdxSource > NumParams)) {
|
||||
Idx = IdxInt.getLimitedValue();
|
||||
if (Idx < 1 || (!IV && Idx > NumParams)) {
|
||||
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
|
||||
<< getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange();
|
||||
<< getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange();
|
||||
return false;
|
||||
}
|
||||
if (HasImplicitThisParam && !CanIndexImplicitThis) {
|
||||
if (IdxSource == 1) {
|
||||
Idx--; // Convert to zero-based.
|
||||
if (HasImplicitThisParam && !AllowImplicitThis) {
|
||||
if (Idx == 0) {
|
||||
S.Diag(getAttrLoc(AI),
|
||||
diag::err_attribute_invalid_implicit_this_argument)
|
||||
<< getAttrName(AI) << IdxExpr->getSourceRange();
|
||||
<< getAttrName(AI) << IdxExpr->getSourceRange();
|
||||
return false;
|
||||
}
|
||||
--Idx;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -771,15 +772,18 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
|
||||
/// AttrArgNo is used to actually retrieve the argument, so it's base-0.
|
||||
template <typename AttrInfo>
|
||||
static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
|
||||
const AttrInfo &AI, unsigned AttrArgNo) {
|
||||
const AttrInfo &AI, unsigned AttrArgNo,
|
||||
bool AllowDependentType = false) {
|
||||
assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument");
|
||||
Expr *AttrArg = AI.getArgAsExpr(AttrArgNo);
|
||||
ParamIdx Idx;
|
||||
uint64_t Idx;
|
||||
if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg,
|
||||
Idx))
|
||||
return false;
|
||||
|
||||
const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex());
|
||||
const ParmVarDecl *Param = FD->getParamDecl(Idx);
|
||||
if (AllowDependentType && Param->getType()->isDependentType())
|
||||
return true;
|
||||
if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) {
|
||||
SourceLocation SrcLoc = AttrArg->getLocStart();
|
||||
S.Diag(SrcLoc, diag::err_attribute_integers_only)
|
||||
@ -802,23 +806,22 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
}
|
||||
|
||||
const Expr *SizeExpr = AL.getArgAsExpr(0);
|
||||
int SizeArgNoVal;
|
||||
int SizeArgNo;
|
||||
// Parameter indices are 1-indexed, hence Index=1
|
||||
if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Index=*/1))
|
||||
if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNo, /*Index=*/1))
|
||||
return;
|
||||
ParamIdx SizeArgNo(SizeArgNoVal, D);
|
||||
|
||||
if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0))
|
||||
return;
|
||||
|
||||
ParamIdx NumberArgNo;
|
||||
// Args are 1-indexed, so 0 implies that the arg was not present
|
||||
int NumberArgNo = 0;
|
||||
if (AL.getNumArgs() == 2) {
|
||||
const Expr *NumberExpr = AL.getArgAsExpr(1);
|
||||
int Val;
|
||||
// Parameter indices are 1-based, hence Index=2
|
||||
if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Index=*/2))
|
||||
if (!checkPositiveIntArgument(S, AL, NumberExpr, NumberArgNo,
|
||||
/*Index=*/2))
|
||||
return;
|
||||
NumberArgNo = ParamIdx(Val, D);
|
||||
|
||||
if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1))
|
||||
return;
|
||||
@ -1421,19 +1424,18 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &AL,
|
||||
}
|
||||
|
||||
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
SmallVector<ParamIdx, 8> NonNullArgs;
|
||||
SmallVector<unsigned, 8> NonNullArgs;
|
||||
for (unsigned I = 0; I < AL.getNumArgs(); ++I) {
|
||||
Expr *Ex = AL.getArgAsExpr(I);
|
||||
ParamIdx Idx;
|
||||
uint64_t Idx;
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx))
|
||||
return;
|
||||
|
||||
// Is the function argument a pointer type?
|
||||
if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) &&
|
||||
!attrNonNullArgCheck(
|
||||
S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL,
|
||||
Ex->getSourceRange(),
|
||||
getFunctionOrMethodParamRange(D, Idx.getASTIndex())))
|
||||
if (Idx < getFunctionOrMethodNumParams(D) &&
|
||||
!attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), AL,
|
||||
Ex->getSourceRange(),
|
||||
getFunctionOrMethodParamRange(D, Idx)))
|
||||
continue;
|
||||
|
||||
NonNullArgs.push_back(Idx);
|
||||
@ -1457,12 +1459,12 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers);
|
||||
}
|
||||
|
||||
ParamIdx *Start = NonNullArgs.data();
|
||||
unsigned *Start = NonNullArgs.data();
|
||||
unsigned Size = NonNullArgs.size();
|
||||
llvm::array_pod_sort(Start, Start + Size);
|
||||
D->addAttr(::new (S.Context)
|
||||
NonNullAttr(AL.getRange(), S.Context, Start, Size,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
NonNullAttr(AL.getRange(), S.Context, Start, Size,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
|
||||
@ -1483,8 +1485,8 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
|
||||
return;
|
||||
|
||||
D->addAttr(::new (S.Context)
|
||||
NonNullAttr(AL.getRange(), S.Context, nullptr, 0,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
NonNullAttr(AL.getRange(), S.Context, nullptr, 0,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleReturnsNonNullAttr(Sema &S, Decl *D,
|
||||
@ -1585,7 +1587,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
|
||||
unsigned SpellingListIndex) {
|
||||
QualType ResultType = getFunctionOrMethodResultType(D);
|
||||
|
||||
AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex);
|
||||
AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex);
|
||||
SourceLocation AttrLoc = AttrRange.getBegin();
|
||||
|
||||
if (!ResultType->isDependentType() &&
|
||||
@ -1595,22 +1597,28 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
|
||||
return;
|
||||
}
|
||||
|
||||
ParamIdx Idx;
|
||||
uint64_t IndexVal;
|
||||
const auto *FuncDecl = cast<FunctionDecl>(D);
|
||||
if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr,
|
||||
/*AttrArgNo=*/1, ParamExpr, Idx))
|
||||
/*AttrArgNo=*/1, ParamExpr,
|
||||
IndexVal))
|
||||
return;
|
||||
|
||||
QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
|
||||
QualType Ty = getFunctionOrMethodParamType(D, IndexVal);
|
||||
if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) {
|
||||
Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only)
|
||||
<< &TmpAttr
|
||||
<< FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange();
|
||||
<< &TmpAttr << FuncDecl->getParamDecl(IndexVal)->getSourceRange();
|
||||
return;
|
||||
}
|
||||
|
||||
D->addAttr(::new (Context)
|
||||
AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex));
|
||||
// We cannot use the Idx returned from checkFunctionOrMethodParameterIndex
|
||||
// because that has corrected for the implicit this parameter, and is zero-
|
||||
// based. The attribute expects what the user wrote explicitly.
|
||||
llvm::APSInt Val;
|
||||
ParamExpr->EvaluateAsInt(Val, Context);
|
||||
|
||||
D->addAttr(::new (Context) AllocAlignAttr(
|
||||
AttrRange, Context, Val.getZExtValue(), SpellingListIndex));
|
||||
}
|
||||
|
||||
/// Normalize the attribute, __foo__ becomes foo.
|
||||
@ -1670,15 +1678,15 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
Module = &S.PP.getIdentifierTable().get(ModuleName);
|
||||
}
|
||||
|
||||
SmallVector<ParamIdx, 8> OwnershipArgs;
|
||||
SmallVector<unsigned, 8> OwnershipArgs;
|
||||
for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
|
||||
Expr *Ex = AL.getArgAsExpr(i);
|
||||
ParamIdx Idx;
|
||||
uint64_t Idx;
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx))
|
||||
return;
|
||||
|
||||
// Is the function argument a pointer type?
|
||||
QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex());
|
||||
QualType T = getFunctionOrMethodParamType(D, Idx);
|
||||
int Err = -1; // No error
|
||||
switch (K) {
|
||||
case OwnershipAttr::Takes:
|
||||
@ -1709,13 +1717,14 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
} else if (K == OwnershipAttr::Returns &&
|
||||
I->getOwnKind() == OwnershipAttr::Returns) {
|
||||
// A returns attribute conflicts with any other returns attribute using
|
||||
// a different index.
|
||||
// a different index. Note, diagnostic reporting is 1-based, but stored
|
||||
// argument indexes are 0-based.
|
||||
if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) {
|
||||
S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch)
|
||||
<< I->args_begin()->getSourceIndex();
|
||||
<< *(I->args_begin()) + 1;
|
||||
if (I->args_size())
|
||||
S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch)
|
||||
<< Idx.getSourceIndex() << Ex->getSourceRange();
|
||||
<< (unsigned)Idx + 1 << Ex->getSourceRange();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1723,12 +1732,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
OwnershipArgs.push_back(Idx);
|
||||
}
|
||||
|
||||
ParamIdx *Start = OwnershipArgs.data();
|
||||
unsigned Size = OwnershipArgs.size();
|
||||
llvm::array_pod_sort(Start, Start + Size);
|
||||
unsigned* start = OwnershipArgs.data();
|
||||
unsigned size = OwnershipArgs.size();
|
||||
llvm::array_pod_sort(start, start + size);
|
||||
|
||||
D->addAttr(::new (S.Context)
|
||||
OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
OwnershipAttr(AL.getLoc(), S.Context, Module, start, size,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
@ -3046,12 +3056,12 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
|
||||
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
Expr *IdxExpr = AL.getArgAsExpr(0);
|
||||
ParamIdx Idx;
|
||||
uint64_t Idx;
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx))
|
||||
return;
|
||||
|
||||
// Make sure the format string is really a string.
|
||||
QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
|
||||
QualType Ty = getFunctionOrMethodParamType(D, Idx);
|
||||
|
||||
bool NotNSStringTy = !isNSStringType(Ty, S.Context);
|
||||
if (NotNSStringTy &&
|
||||
@ -3074,8 +3084,15 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
return;
|
||||
}
|
||||
|
||||
D->addAttr(::new (S.Context) FormatArgAttr(
|
||||
AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex()));
|
||||
// We cannot use the Idx returned from checkFunctionOrMethodParameterIndex
|
||||
// because that has corrected for the implicit this parameter, and is zero-
|
||||
// based. The attribute expects what the user wrote explicitly.
|
||||
llvm::APSInt Val;
|
||||
IdxExpr->EvaluateAsInt(Val, S.Context);
|
||||
|
||||
D->addAttr(::new (S.Context)
|
||||
FormatArgAttr(AL.getRange(), S.Context, Val.getZExtValue(),
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
enum FormatAttrKind {
|
||||
@ -4469,13 +4486,13 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
|
||||
<< AL.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier;
|
||||
return;
|
||||
}
|
||||
|
||||
ParamIdx ArgumentIdx;
|
||||
|
||||
uint64_t ArgumentIdx;
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1),
|
||||
ArgumentIdx))
|
||||
return;
|
||||
|
||||
ParamIdx TypeTagIdx;
|
||||
uint64_t TypeTagIdx;
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2),
|
||||
TypeTagIdx))
|
||||
return;
|
||||
@ -4483,9 +4500,8 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
|
||||
bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag";
|
||||
if (IsPointer) {
|
||||
// Ensure that buffer has a pointer type.
|
||||
unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex();
|
||||
if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) ||
|
||||
!getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType())
|
||||
if (ArgumentIdx >= getFunctionOrMethodNumParams(D) ||
|
||||
!getFunctionOrMethodParamType(D, ArgumentIdx)->isPointerType())
|
||||
S.Diag(AL.getLoc(), diag::err_attribute_pointers_only)
|
||||
<< AL.getName() << 0;
|
||||
}
|
||||
@ -4525,18 +4541,19 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleXRayLogArgsAttr(Sema &S, Decl *D, const AttributeList &AL) {
|
||||
ParamIdx ArgCount;
|
||||
static void handleXRayLogArgsAttr(Sema &S, Decl *D,
|
||||
const AttributeList &AL) {
|
||||
uint64_t ArgCount;
|
||||
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0),
|
||||
ArgCount,
|
||||
true /* CanIndexImplicitThis */))
|
||||
true /* AllowImplicitThis*/))
|
||||
return;
|
||||
|
||||
// ArgCount isn't a parameter index [0;n), it's a count [1;n]
|
||||
D->addAttr(::new (S.Context) XRayLogArgsAttr(
|
||||
AL.getRange(), S.Context, ArgCount.getSourceIndex(),
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
// ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1.
|
||||
D->addAttr(::new (S.Context)
|
||||
XRayLogArgsAttr(AL.getRange(), S.Context, ++ArgCount,
|
||||
AL.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -176,7 +176,7 @@ static void instantiateDependentAllocAlignAttr(
|
||||
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
const AllocAlignAttr *Align, Decl *New) {
|
||||
Expr *Param = IntegerLiteral::Create(
|
||||
S.getASTContext(), llvm::APInt(64, Align->paramIndex().getSourceIndex()),
|
||||
S.getASTContext(), llvm::APInt(64, Align->getParamIndex()),
|
||||
S.getASTContext().UnsignedLongLongTy, Align->getLocation());
|
||||
S.AddAllocAlignAttr(Align->getLocation(), New, Param,
|
||||
Align->getSpellingListIndex());
|
||||
|
@ -1231,10 +1231,9 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
|
||||
if (Att->getModule() != II_malloc)
|
||||
return nullptr;
|
||||
|
||||
ParamIdx *I = Att->args_begin(), *E = Att->args_end();
|
||||
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
|
||||
if (I != E) {
|
||||
return MallocMemAux(C, CE, CE->getArg(I->getASTIndex()), UndefinedVal(),
|
||||
State);
|
||||
return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), State);
|
||||
}
|
||||
return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State);
|
||||
}
|
||||
@ -1332,9 +1331,9 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
|
||||
bool ReleasedAllocated = false;
|
||||
|
||||
for (const auto &Arg : Att->args()) {
|
||||
ProgramStateRef StateI = FreeMemAux(
|
||||
C, CE, State, Arg.getASTIndex(),
|
||||
Att->getOwnKind() == OwnershipAttr::Holds, ReleasedAllocated);
|
||||
ProgramStateRef StateI = FreeMemAux(C, CE, State, Arg,
|
||||
Att->getOwnKind() == OwnershipAttr::Holds,
|
||||
ReleasedAllocated);
|
||||
if (StateI)
|
||||
State = StateI;
|
||||
}
|
||||
|
@ -58,11 +58,10 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
|
||||
AttrNonNull.set(0, NumArgs);
|
||||
break;
|
||||
}
|
||||
for (const ParamIdx &Idx : NonNull->args()) {
|
||||
unsigned IdxAST = Idx.getASTIndex();
|
||||
if (IdxAST >= NumArgs)
|
||||
for (unsigned Val : NonNull->args()) {
|
||||
if (Val >= NumArgs)
|
||||
continue;
|
||||
AttrNonNull.set(IdxAST);
|
||||
AttrNonNull.set(Val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,24 +71,6 @@ int testIt() {
|
||||
}
|
||||
} // namespace templated_alloc_size
|
||||
|
||||
class C {
|
||||
public:
|
||||
void *my_malloc(int N) __attribute__((alloc_size(2)));
|
||||
void *my_calloc(int N, int M) __attribute__((alloc_size(2, 3)));
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define i32 @_Z16callMemberMallocv
|
||||
int callMemberMalloc() {
|
||||
// CHECK: ret i32 16
|
||||
return __builtin_object_size(C().my_malloc(16), 0);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define i32 @_Z16callMemberCallocv
|
||||
int callMemberCalloc() {
|
||||
// CHECK: ret i32 32
|
||||
return __builtin_object_size(C().my_calloc(16, 2), 0);
|
||||
}
|
||||
|
||||
struct D {
|
||||
~D();
|
||||
void *my_malloc(int N) __attribute__((alloc_size(2)));
|
||||
|
@ -68,12 +68,12 @@ __attribute__((pointer_with_type_tag(ident1,1,2)));
|
||||
void TestBool(void *, int)
|
||||
__attribute__((pointer_with_type_tag(bool1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestBool
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}}pointer_with_type_tag bool1 1 2 IsPointer
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}}pointer_with_type_tag bool1 0 1 IsPointer
|
||||
|
||||
void TestUnsigned(void *, int)
|
||||
__attribute__((pointer_with_type_tag(unsigned1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestUnsigned
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag unsigned1 1 2
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag unsigned1 0 1
|
||||
|
||||
void TestInt(void) __attribute__((constructor(123)));
|
||||
// CHECK: FunctionDecl{{.*}}TestInt
|
||||
|
@ -1,7 +0,0 @@
|
||||
// RUN: %clang_cc1 %s -verify -fsyntax-only
|
||||
|
||||
class C {
|
||||
void f(int, int)
|
||||
__attribute__((ownership_returns(foo, 2))) // expected-note {{declared with index 2 here}}
|
||||
__attribute__((ownership_returns(foo, 3))); // expected-error {{'ownership_returns' attribute index does not match; here it is 3}}
|
||||
};
|
@ -1,67 +1,6 @@
|
||||
// RUN: %clang_cc1 %s -ast-print | FileCheck %s
|
||||
|
||||
// CHECK: void xla(int a) __attribute__((xray_log_args(1)));
|
||||
void xla(int a) __attribute__((xray_log_args(1)));
|
||||
|
||||
// CHECK: void *as2(int, int) __attribute__((alloc_size(1, 2)));
|
||||
void *as2(int, int) __attribute__((alloc_size(1, 2)));
|
||||
// CHECK: void *as1(void *, int) __attribute__((alloc_size(2)));
|
||||
void *as1(void *, int) __attribute__((alloc_size(2)));
|
||||
|
||||
// CHECK: void fmt(int, const char *, ...) __attribute__((format(printf, 2, 3)));
|
||||
void fmt(int, const char *, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
// CHECK: char *fmta(int, const char *) __attribute__((format_arg(2)));
|
||||
char *fmta(int, const char *) __attribute__((format_arg(2)));
|
||||
|
||||
// CHECK: void nn(int *, int *) __attribute__((nonnull(1, 2)));
|
||||
void nn(int *, int *) __attribute__((nonnull(1, 2)));
|
||||
|
||||
// CHECK: int *aa(int i) __attribute__((alloc_align(1)));
|
||||
int *aa(int i) __attribute__((alloc_align(1)));
|
||||
|
||||
// CHECK: void ownt(int *, int *) __attribute__((ownership_takes(foo, 1, 2)));
|
||||
void ownt(int *, int *) __attribute__((ownership_takes(foo, 1, 2)));
|
||||
// CHECK: void ownh(int *, int *) __attribute__((ownership_holds(foo, 1, 2)));
|
||||
void ownh(int *, int *) __attribute__((ownership_holds(foo, 1, 2)));
|
||||
// CHECK: void ownr(int) __attribute__((ownership_returns(foo, 1)));
|
||||
void ownr(int) __attribute__((ownership_returns(foo, 1)));
|
||||
|
||||
// CHECK: void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 3, 2)));
|
||||
void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 3, 2)));
|
||||
// CHECK: void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, 1, 2)));
|
||||
void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, 1, 2)));
|
||||
|
||||
class C {
|
||||
// CHECK: void xla(int a) __attribute__((xray_log_args(2)));
|
||||
void xla(int a) __attribute__((xray_log_args(2)));
|
||||
|
||||
// CHECK: void *as2(int, int) __attribute__((alloc_size(2, 3)));
|
||||
void *as2(int, int) __attribute__((alloc_size(2, 3)));
|
||||
// CHECK: void *as1(void *, int) __attribute__((alloc_size(3)));
|
||||
void *as1(void *, int) __attribute__((alloc_size(3)));
|
||||
|
||||
// CHECK: void fmt(int, const char *, ...) __attribute__((format(printf, 3, 4)));
|
||||
void fmt(int, const char *, ...) __attribute__((format(printf, 3, 4)));
|
||||
|
||||
// CHECK: char *fmta(int, const char *) __attribute__((format_arg(3)));
|
||||
char *fmta(int, const char *) __attribute__((format_arg(3)));
|
||||
|
||||
// CHECK: void nn(int *, int *) __attribute__((nonnull(2, 3)));
|
||||
void nn(int *, int *) __attribute__((nonnull(2, 3)));
|
||||
|
||||
// CHECK: int *aa(int i) __attribute__((alloc_align(2)));
|
||||
int *aa(int i) __attribute__((alloc_align(2)));
|
||||
|
||||
// CHECK: void ownt(int *, int *) __attribute__((ownership_takes(foo, 2, 3)));
|
||||
void ownt(int *, int *) __attribute__((ownership_takes(foo, 2, 3)));
|
||||
// CHECK: void ownh(int *, int *) __attribute__((ownership_holds(foo, 2, 3)));
|
||||
void ownh(int *, int *) __attribute__((ownership_holds(foo, 2, 3)));
|
||||
// CHECK: void ownr(int) __attribute__((ownership_returns(foo, 2)));
|
||||
void ownr(int) __attribute__((ownership_returns(foo, 2)));
|
||||
|
||||
// CHECK: void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 4, 3)));
|
||||
void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 4, 3)));
|
||||
// CHECK: void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, 2, 3)));
|
||||
void pwtt(void *, int) __attribute__((pointer_with_type_tag(foo, 2, 3)));
|
||||
};
|
||||
|
@ -3,50 +3,21 @@
|
||||
#define INT_TAG 42
|
||||
|
||||
static const int test_in
|
||||
__attribute__((type_tag_for_datatype(test, int))) = INT_TAG;
|
||||
__attribute__((type_tag_for_datatype(test, int))) = INT_TAG;
|
||||
|
||||
// Argument index: 1, Type tag index: 2
|
||||
void test_bounds_index(...)
|
||||
__attribute__((argument_with_type_tag(test, 1, 2)));
|
||||
|
||||
// Argument index: 1, Type tag index: 2
|
||||
void test_bounds_index_ptr(void *, ...)
|
||||
__attribute__((pointer_with_type_tag(test, 1, 2)));
|
||||
__attribute__((argument_with_type_tag(test, 1, 2)));
|
||||
|
||||
// Argument index: 3, Type tag index: 1
|
||||
void test_bounds_arg_index(...)
|
||||
__attribute__((argument_with_type_tag(test, 3, 1)));
|
||||
|
||||
class C {
|
||||
public:
|
||||
// Argument index: 2, Type tag index: 3
|
||||
void test_bounds_index(...)
|
||||
__attribute__((argument_with_type_tag(test, 2, 3)));
|
||||
|
||||
// Argument index: 2, Type tag index: 3
|
||||
void test_bounds_index_ptr(void *, ...)
|
||||
__attribute__((pointer_with_type_tag(test, 2, 3)));
|
||||
|
||||
// Argument index: 4, Type tag index: 2
|
||||
void test_bounds_arg_index(...)
|
||||
__attribute__((argument_with_type_tag(test, 4, 2)));
|
||||
};
|
||||
__attribute__((argument_with_type_tag(test, 3, 1)));
|
||||
|
||||
void test_bounds()
|
||||
{
|
||||
C c;
|
||||
|
||||
// Test the boundary edges (ensure no off-by-one) with argument indexing.
|
||||
test_bounds_index(1, INT_TAG);
|
||||
c.test_bounds_index(1, INT_TAG);
|
||||
test_bounds_index_ptr(0, INT_TAG);
|
||||
c.test_bounds_index_ptr(0, INT_TAG);
|
||||
|
||||
test_bounds_index(1); // expected-error {{type tag index 2 is greater than the number of arguments specified}}
|
||||
c.test_bounds_index(1); // expected-error {{type tag index 3 is greater than the number of arguments specified}}
|
||||
test_bounds_index_ptr(0); // expected-error {{type tag index 2 is greater than the number of arguments specified}}
|
||||
c.test_bounds_index_ptr(0); // expected-error {{type tag index 3 is greater than the number of arguments specified}}
|
||||
|
||||
test_bounds_arg_index(INT_TAG, 1); // expected-error {{argument index 3 is greater than the number of arguments specified}}
|
||||
c.test_bounds_arg_index(INT_TAG, 1); // expected-error {{argument index 4 is greater than the number of arguments specified}}
|
||||
test_bounds_index(1); // expected-error {{type tag index 2 is greater than the number of arguments specified}}
|
||||
test_bounds_arg_index(INT_TAG, 1); // expected-error {{argument index 3 is greater than the number of arguments specified}}
|
||||
}
|
||||
|
@ -302,6 +302,9 @@ namespace {
|
||||
std::string getIsOmitted() const override {
|
||||
if (type == "IdentifierInfo *")
|
||||
return "!get" + getUpperName().str() + "()";
|
||||
// FIXME: Do this declaratively in Attr.td.
|
||||
if (getAttrName() == "AllocSize")
|
||||
return "0 == get" + getUpperName().str() + "()";
|
||||
return "false";
|
||||
}
|
||||
|
||||
@ -745,138 +748,6 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
class VariadicParamIdxArgument : public VariadicArgument {
|
||||
public:
|
||||
VariadicParamIdxArgument(const Record &Arg, StringRef Attr)
|
||||
: VariadicArgument(Arg, Attr, "ParamIdx") {}
|
||||
|
||||
public:
|
||||
void writeCtorBody(raw_ostream &OS) const override {
|
||||
VariadicArgument::writeCtorBody(OS);
|
||||
OS << " #ifndef NDEBUG\n"
|
||||
<< " if (" << getLowerName() << "_size()) {\n"
|
||||
<< " bool HasThis = " << getLowerName()
|
||||
<< "_begin()->hasThis();\n"
|
||||
<< " for (const auto Idx : " << getLowerName() << "()) {\n"
|
||||
<< " assert(Idx.isValid() && \"ParamIdx must be valid\");\n"
|
||||
<< " assert(HasThis == Idx.hasThis() && "
|
||||
<< "\"HasThis must be consistent\");\n"
|
||||
<< " }\n"
|
||||
<< " }\n"
|
||||
<< " #endif\n";
|
||||
}
|
||||
|
||||
void writePCHReadDecls(raw_ostream &OS) const override {
|
||||
OS << " unsigned " << getUpperName() << "Size = Record.readInt();\n";
|
||||
OS << " bool " << getUpperName() << "HasThis = " << getUpperName()
|
||||
<< "Size ? Record.readInt() : false;\n";
|
||||
OS << " SmallVector<ParamIdx, 4> " << getUpperName() << ";\n"
|
||||
<< " " << getUpperName() << ".reserve(" << getUpperName()
|
||||
<< "Size);\n"
|
||||
<< " for (unsigned i = 0; i != " << getUpperName()
|
||||
<< "Size; ++i) {\n"
|
||||
<< " " << getUpperName()
|
||||
<< ".push_back(ParamIdx(Record.readInt(), " << getUpperName()
|
||||
<< "HasThis));\n"
|
||||
<< " }\n";
|
||||
}
|
||||
|
||||
void writePCHReadArgs(raw_ostream &OS) const override {
|
||||
OS << getUpperName() << ".data(), " << getUpperName() << "Size";
|
||||
}
|
||||
|
||||
void writePCHWrite(raw_ostream &OS) const override {
|
||||
OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
|
||||
OS << " if (SA->" << getLowerName() << "_size())\n"
|
||||
<< " Record.push_back(SA->" << getLowerName()
|
||||
<< "_begin()->hasThis());\n";
|
||||
OS << " for (auto Idx : SA->" << getLowerName() << "())\n"
|
||||
<< " Record.push_back(Idx.getSourceIndex());\n";
|
||||
}
|
||||
|
||||
void writeValueImpl(raw_ostream &OS) const override {
|
||||
OS << " OS << Val.getSourceIndex();\n";
|
||||
}
|
||||
|
||||
void writeDump(raw_ostream &OS) const override {
|
||||
OS << " for (auto Idx : SA->" << getLowerName() << "())\n";
|
||||
OS << " OS << \" \" << Idx.getSourceIndex();\n";
|
||||
}
|
||||
};
|
||||
|
||||
class ParamIdxArgument : public Argument {
|
||||
std::string IdxName;
|
||||
|
||||
public:
|
||||
ParamIdxArgument(const Record &Arg, StringRef Attr)
|
||||
: Argument(Arg, Attr), IdxName(getUpperName()) {}
|
||||
|
||||
void writeDeclarations(raw_ostream &OS) const override {
|
||||
OS << "ParamIdx " << IdxName << ";\n";
|
||||
}
|
||||
|
||||
void writeAccessors(raw_ostream &OS) const override {
|
||||
OS << "\n"
|
||||
<< " ParamIdx " << getLowerName() << "() const {"
|
||||
<< " return " << IdxName << "; }\n";
|
||||
}
|
||||
|
||||
void writeCtorParameters(raw_ostream &OS) const override {
|
||||
OS << "ParamIdx " << IdxName;
|
||||
}
|
||||
|
||||
void writeCloneArgs(raw_ostream &OS) const override { OS << IdxName; }
|
||||
|
||||
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
||||
OS << "A->" << getLowerName() << "()";
|
||||
}
|
||||
|
||||
void writeImplicitCtorArgs(raw_ostream &OS) const override {
|
||||
OS << IdxName;
|
||||
}
|
||||
|
||||
void writeCtorInitializers(raw_ostream &OS) const override {
|
||||
OS << IdxName << "(" << IdxName << ")";
|
||||
}
|
||||
|
||||
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
|
||||
OS << IdxName << "()";
|
||||
}
|
||||
|
||||
void writePCHReadDecls(raw_ostream &OS) const override {
|
||||
OS << " unsigned " << IdxName << "Src = Record.readInt();\n";
|
||||
OS << " bool " << IdxName << "HasThis = Record.readInt();\n";
|
||||
}
|
||||
|
||||
void writePCHReadArgs(raw_ostream &OS) const override {
|
||||
OS << "ParamIdx(" << IdxName << "Src, " << IdxName << "HasThis)";
|
||||
}
|
||||
|
||||
void writePCHWrite(raw_ostream &OS) const override {
|
||||
OS << " Record.push_back(SA->" << getLowerName()
|
||||
<< "().isValid() ? SA->" << getLowerName()
|
||||
<< "().getSourceIndex() : 0);\n";
|
||||
OS << " Record.push_back(SA->" << getLowerName()
|
||||
<< "().isValid() ? SA->" << getLowerName()
|
||||
<< "().hasThis() : false);\n";
|
||||
}
|
||||
|
||||
std::string getIsOmitted() const override {
|
||||
return "!" + IdxName + ".isValid()";
|
||||
}
|
||||
|
||||
void writeValue(raw_ostream &OS) const override {
|
||||
OS << "\" << " << IdxName << ".getSourceIndex() << \"";
|
||||
}
|
||||
|
||||
void writeDump(raw_ostream &OS) const override {
|
||||
if (isOptional())
|
||||
OS << " if (SA->" << getLowerName() << "().isValid())\n ";
|
||||
OS << " OS << \" \" << SA->" << getLowerName()
|
||||
<< "().getSourceIndex();\n";
|
||||
}
|
||||
};
|
||||
|
||||
// Unique the enums, but maintain the original declaration ordering.
|
||||
std::vector<StringRef>
|
||||
uniqueEnumsInOrder(const std::vector<StringRef> &enums) {
|
||||
@ -1376,10 +1247,6 @@ createArgument(const Record &Arg, StringRef Attr,
|
||||
Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
|
||||
else if (ArgName == "VariadicExprArgument")
|
||||
Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
|
||||
else if (ArgName == "VariadicParamIdxArgument")
|
||||
Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr);
|
||||
else if (ArgName == "ParamIdxArgument")
|
||||
Ptr = llvm::make_unique<ParamIdxArgument>(Arg, Attr);
|
||||
else if (ArgName == "VersionArgument")
|
||||
Ptr = llvm::make_unique<VersionArgument>(Arg, Attr);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user