[AsmParser] Unify parsing of attributes

Continuing on from D105780, this should be the last major bit of
attribute cleanup. Currently, LLParser implements attribute parsing
for functions, parameters and returns separately, enumerating all
supported (and unsupported) attributes each time. This patch
extracts the common parsing logic, and performs a check afterwards
whether the attribute is valid in the given position. Parameters
and returns are handled together, while function attributes need
slightly different logic to support attribute groups.

Differential Revision: https://reviews.llvm.org/D105938
This commit is contained in:
Nikita Popov 2021-07-13 22:14:55 +02:00
parent e33446ea58
commit f59209a86e
16 changed files with 154 additions and 441 deletions

View File

@ -258,8 +258,15 @@ namespace llvm {
return parseOptionalAddrSpace(
AddrSpace, M->getDataLayout().getProgramAddressSpace());
};
bool parseOptionalParamAttrs(AttrBuilder &B);
bool parseOptionalReturnAttrs(AttrBuilder &B);
bool parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
bool InAttrGroup);
bool parseOptionalParamOrReturnAttrs(AttrBuilder &B, bool IsParam);
bool parseOptionalParamAttrs(AttrBuilder &B) {
return parseOptionalParamOrReturnAttrs(B, true);
}
bool parseOptionalReturnAttrs(AttrBuilder &B) {
return parseOptionalParamOrReturnAttrs(B, false);
}
bool parseOptionalLinkage(unsigned &Res, bool &HasLinkage,
unsigned &Visibility, unsigned &DLLStorageClass,
bool &DSOLocal);

View File

@ -1243,212 +1243,144 @@ bool LLParser::parseUnnamedAttrGrp() {
return false;
}
static Attribute::AttrKind tokenToAttribute(lltok::Kind Kind) {
switch (Kind) {
#define GET_ATTR_NAMES
#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
case lltok::kw_##DISPLAY_NAME: \
return Attribute::ENUM_NAME;
#include "llvm/IR/Attributes.inc"
default:
return Attribute::None;
}
}
bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
bool InAttrGroup) {
if (Attribute::isTypeAttrKind(Attr))
return parseRequiredTypeAttr(B, Lex.getKind(), Attr);
switch (Attr) {
case Attribute::Alignment: {
MaybeAlign Alignment;
if (InAttrGroup) {
uint32_t Value = 0;
Lex.Lex();
if (parseToken(lltok::equal, "expected '=' here") || parseUInt32(Value))
return true;
Alignment = Align(Value);
} else {
if (parseOptionalAlignment(Alignment, true))
return true;
}
B.addAlignmentAttr(Alignment);
return false;
}
case Attribute::StackAlignment: {
unsigned Alignment;
if (InAttrGroup) {
Lex.Lex();
if (parseToken(lltok::equal, "expected '=' here") ||
parseUInt32(Alignment))
return true;
} else {
if (parseOptionalStackAlignment(Alignment))
return true;
}
B.addStackAlignmentAttr(Alignment);
return false;
}
case Attribute::AllocSize: {
unsigned ElemSizeArg;
Optional<unsigned> NumElemsArg;
if (parseAllocSizeArguments(ElemSizeArg, NumElemsArg))
return true;
B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
return false;
}
case Attribute::VScaleRange: {
unsigned MinValue, MaxValue;
if (parseVScaleRangeArguments(MinValue, MaxValue))
return true;
B.addVScaleRangeAttr(MinValue, MaxValue);
return false;
}
case Attribute::Dereferenceable: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
return true;
B.addDereferenceableAttr(Bytes);
return false;
}
case Attribute::DereferenceableOrNull: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
return true;
B.addDereferenceableOrNullAttr(Bytes);
return false;
}
default:
B.addAttribute(Attr);
Lex.Lex();
return false;
}
}
/// parseFnAttributeValuePairs
/// ::= <attr> | <attr> '=' <value>
bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &BuiltinLoc) {
bool InAttrGrp, LocTy &BuiltinLoc) {
bool HaveError = false;
B.clear();
while (true) {
lltok::Kind Token = Lex.getKind();
if (Token == lltok::kw_builtin)
BuiltinLoc = Lex.getLoc();
switch (Token) {
default:
if (!inAttrGrp) return HaveError;
return error(Lex.getLoc(), "unterminated attribute group");
case lltok::rbrace:
// Finished.
return false;
if (Token == lltok::rbrace)
return HaveError; // Finished.
case lltok::AttrGrpID: {
// Allow a function to reference an attribute group:
//
// define void @foo() #1 { ... }
if (inAttrGrp)
HaveError |= error(
Lex.getLoc(),
"cannot have an attribute group reference in an attribute group");
unsigned AttrGrpNum = Lex.getUIntVal();
if (inAttrGrp) break;
// Save the reference to the attribute group. We'll fill it in later.
FwdRefAttrGrps.push_back(AttrGrpNum);
break;
}
// Target-dependent attributes:
case lltok::StringConstant: {
if (Token == lltok::StringConstant) {
if (parseStringAttribute(B))
return true;
continue;
}
// Target-independent attributes:
case lltok::kw_align: {
// As a hack, we allow function alignment to be initially parsed as an
// attribute on a function declaration/definition or added to an attribute
// group and later moved to the alignment field.
MaybeAlign Alignment;
if (inAttrGrp) {
Lex.Lex();
uint32_t Value = 0;
if (parseToken(lltok::equal, "expected '=' here") || parseUInt32(Value))
return true;
Alignment = Align(Value);
if (Token == lltok::AttrGrpID) {
// Allow a function to reference an attribute group:
//
// define void @foo() #1 { ... }
if (InAttrGrp) {
HaveError |= error(
Lex.getLoc(),
"cannot have an attribute group reference in an attribute group");
} else {
if (parseOptionalAlignment(Alignment))
return true;
// Save the reference to the attribute group. We'll fill it in later.
FwdRefAttrGrps.push_back(Lex.getUIntVal());
}
B.addAlignmentAttr(Alignment);
continue;
}
case lltok::kw_alignstack: {
unsigned Alignment;
if (inAttrGrp) {
Lex.Lex();
if (parseToken(lltok::equal, "expected '=' here") ||
parseUInt32(Alignment))
return true;
} else {
if (parseOptionalStackAlignment(Alignment))
return true;
}
B.addStackAlignmentAttr(Alignment);
continue;
}
case lltok::kw_allocsize: {
unsigned ElemSizeArg;
Optional<unsigned> NumElemsArg;
// inAttrGrp doesn't matter; we only support allocsize(a[, b])
if (parseAllocSizeArguments(ElemSizeArg, NumElemsArg))
return true;
B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
continue;
}
case lltok::kw_vscale_range: {
unsigned MinValue, MaxValue;
// inAttrGrp doesn't matter; we only support vscale_range(a[, b])
if (parseVScaleRangeArguments(MinValue, MaxValue))
return true;
B.addVScaleRangeAttr(MinValue, MaxValue);
continue;
}
case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break;
case lltok::kw_argmemonly: B.addAttribute(Attribute::ArgMemOnly); break;
case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break;
case lltok::kw_cold: B.addAttribute(Attribute::Cold); break;
case lltok::kw_hot: B.addAttribute(Attribute::Hot); break;
case lltok::kw_convergent: B.addAttribute(Attribute::Convergent); break;
case lltok::kw_inaccessiblememonly:
B.addAttribute(Attribute::InaccessibleMemOnly); break;
case lltok::kw_inaccessiblemem_or_argmemonly:
B.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); break;
case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break;
case lltok::kw_jumptable: B.addAttribute(Attribute::JumpTable); break;
case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break;
case lltok::kw_mustprogress:
B.addAttribute(Attribute::MustProgress);
break;
case lltok::kw_naked: B.addAttribute(Attribute::Naked); break;
case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin); break;
case lltok::kw_nocallback:
B.addAttribute(Attribute::NoCallback);
break;
case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break;
case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break;
case lltok::kw_noimplicitfloat:
B.addAttribute(Attribute::NoImplicitFloat); break;
case lltok::kw_noinline: B.addAttribute(Attribute::NoInline); break;
case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break;
case lltok::kw_nomerge: B.addAttribute(Attribute::NoMerge); break;
case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break;
case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break;
case lltok::kw_nosync: B.addAttribute(Attribute::NoSync); break;
case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
case lltok::kw_noprofile: B.addAttribute(Attribute::NoProfile); break;
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
case lltok::kw_nosanitize_coverage:
B.addAttribute(Attribute::NoSanitizeCoverage);
break;
case lltok::kw_null_pointer_is_valid:
B.addAttribute(Attribute::NullPointerIsValid); break;
case lltok::kw_optforfuzzing:
B.addAttribute(Attribute::OptForFuzzing); break;
case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break;
case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break;
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
case lltok::kw_returns_twice:
B.addAttribute(Attribute::ReturnsTwice); break;
case lltok::kw_speculatable: B.addAttribute(Attribute::Speculatable); break;
case lltok::kw_ssp: B.addAttribute(Attribute::StackProtect); break;
case lltok::kw_sspreq: B.addAttribute(Attribute::StackProtectReq); break;
case lltok::kw_sspstrong:
B.addAttribute(Attribute::StackProtectStrong); break;
case lltok::kw_safestack: B.addAttribute(Attribute::SafeStack); break;
case lltok::kw_shadowcallstack:
B.addAttribute(Attribute::ShadowCallStack); break;
case lltok::kw_sanitize_address:
B.addAttribute(Attribute::SanitizeAddress); break;
case lltok::kw_sanitize_hwaddress:
B.addAttribute(Attribute::SanitizeHWAddress); break;
case lltok::kw_sanitize_memtag:
B.addAttribute(Attribute::SanitizeMemTag); break;
case lltok::kw_sanitize_thread:
B.addAttribute(Attribute::SanitizeThread); break;
case lltok::kw_sanitize_memory:
B.addAttribute(Attribute::SanitizeMemory); break;
case lltok::kw_speculative_load_hardening:
B.addAttribute(Attribute::SpeculativeLoadHardening);
break;
case lltok::kw_strictfp: B.addAttribute(Attribute::StrictFP); break;
case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break;
case lltok::kw_willreturn: B.addAttribute(Attribute::WillReturn); break;
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
case lltok::kw_preallocated: {
if (parseRequiredTypeAttr(B, lltok::kw_preallocated,
Attribute::Preallocated))
return true;
break;
}
// error handling.
case lltok::kw_inreg:
case lltok::kw_signext:
case lltok::kw_zeroext:
HaveError |=
error(Lex.getLoc(), "invalid use of attribute on a function");
break;
case lltok::kw_byval:
case lltok::kw_dereferenceable:
case lltok::kw_dereferenceable_or_null:
case lltok::kw_inalloca:
case lltok::kw_nest:
case lltok::kw_noalias:
case lltok::kw_noundef:
case lltok::kw_nocapture:
case lltok::kw_nonnull:
case lltok::kw_returned:
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
case lltok::kw_swiftasync:
case lltok::kw_immarg:
case lltok::kw_byref:
HaveError |=
error(Lex.getLoc(),
"invalid use of parameter-only attribute on a function");
break;
}
// parsePreallocated() consumes token
if (Token != lltok::kw_preallocated)
Lex.Lex();
continue;
}
SMLoc Loc = Lex.getLoc();
if (Token == lltok::kw_builtin)
BuiltinLoc = Loc;
Attribute::AttrKind Attr = tokenToAttribute(Token);
if (Attr == Attribute::None) {
if (!InAttrGrp)
return HaveError;
return error(Lex.getLoc(), "unterminated attribute group");
}
if (parseEnumAttribute(Attr, B, InAttrGrp))
return true;
// As a hack, we allow function alignment to be initially parsed as an
// attribute on a function declaration/definition or added to an attribute
// group and later moved to the alignment field.
if (!Attribute::canUseAsFnAttr(Attr) && Attr != Attribute::Alignment)
HaveError |= error(Loc, "this attribute does not apply to functions");
}
}
@ -1685,258 +1617,32 @@ bool LLParser::parseStringAttribute(AttrBuilder &B) {
return false;
}
/// parseOptionalParamAttrs - parse a potentially empty list of parameter
/// attributes.
bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) {
/// Parse a potentially empty list of parameter or return attributes.
bool LLParser::parseOptionalParamOrReturnAttrs(AttrBuilder &B, bool IsParam) {
bool HaveError = false;
B.clear();
while (true) {
lltok::Kind Token = Lex.getKind();
switch (Token) {
default: // End of attributes.
return HaveError;
case lltok::StringConstant: {
if (Token == lltok::StringConstant) {
if (parseStringAttribute(B))
return true;
continue;
}
case lltok::kw_align: {
MaybeAlign Alignment;
if (parseOptionalAlignment(Alignment, true))
return true;
B.addAlignmentAttr(Alignment);
continue;
}
case lltok::kw_alignstack: {
unsigned Alignment;
if (parseOptionalStackAlignment(Alignment))
return true;
B.addStackAlignmentAttr(Alignment);
continue;
}
case lltok::kw_byval:
if (parseRequiredTypeAttr(B, lltok::kw_byval, Attribute::ByVal))
return true;
continue;
case lltok::kw_byref:
if (parseRequiredTypeAttr(B, lltok::kw_byref, Attribute::ByRef))
return true;
continue;
case lltok::kw_inalloca:
if (parseRequiredTypeAttr(B, lltok::kw_inalloca, Attribute::InAlloca))
return true;
continue;
case lltok::kw_preallocated:
if (parseRequiredTypeAttr(B, lltok::kw_preallocated,
Attribute::Preallocated))
return true;
continue;
case lltok::kw_sret:
if (parseRequiredTypeAttr(B, lltok::kw_sret, Attribute::StructRet))
return true;
continue;
case lltok::kw_dereferenceable: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
return true;
B.addDereferenceableAttr(Bytes);
continue;
}
case lltok::kw_dereferenceable_or_null: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
return true;
B.addDereferenceableOrNullAttr(Bytes);
continue;
}
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
case lltok::kw_noundef:
B.addAttribute(Attribute::NoUndef);
break;
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break;
case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break;
case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break;
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break;
case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
case lltok::kw_swiftasync: B.addAttribute(Attribute::SwiftAsync); break;
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
case lltok::kw_immarg: B.addAttribute(Attribute::ImmArg); break;
case lltok::kw_alwaysinline:
case lltok::kw_argmemonly:
case lltok::kw_builtin:
case lltok::kw_inlinehint:
case lltok::kw_jumptable:
case lltok::kw_minsize:
case lltok::kw_mustprogress:
case lltok::kw_naked:
case lltok::kw_nobuiltin:
case lltok::kw_noduplicate:
case lltok::kw_noimplicitfloat:
case lltok::kw_noinline:
case lltok::kw_nonlazybind:
case lltok::kw_nomerge:
case lltok::kw_noprofile:
case lltok::kw_noredzone:
case lltok::kw_noreturn:
case lltok::kw_nocf_check:
case lltok::kw_nounwind:
case lltok::kw_nosanitize_coverage:
case lltok::kw_optforfuzzing:
case lltok::kw_optnone:
case lltok::kw_optsize:
case lltok::kw_returns_twice:
case lltok::kw_sanitize_address:
case lltok::kw_sanitize_hwaddress:
case lltok::kw_sanitize_memtag:
case lltok::kw_sanitize_memory:
case lltok::kw_sanitize_thread:
case lltok::kw_speculative_load_hardening:
case lltok::kw_ssp:
case lltok::kw_sspreq:
case lltok::kw_sspstrong:
case lltok::kw_safestack:
case lltok::kw_shadowcallstack:
case lltok::kw_strictfp:
case lltok::kw_uwtable:
case lltok::kw_vscale_range:
HaveError |=
error(Lex.getLoc(), "invalid use of function-only attribute");
break;
}
Lex.Lex();
}
}
/// parseOptionalReturnAttrs - parse a potentially empty list of return
/// attributes.
bool LLParser::parseOptionalReturnAttrs(AttrBuilder &B) {
bool HaveError = false;
B.clear();
while (true) {
lltok::Kind Token = Lex.getKind();
switch (Token) {
default: // End of attributes.
SMLoc Loc = Lex.getLoc();
Attribute::AttrKind Attr = tokenToAttribute(Token);
if (Attr == Attribute::None)
return HaveError;
case lltok::StringConstant: {
if (parseStringAttribute(B))
return true;
continue;
}
case lltok::kw_dereferenceable: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
return true;
B.addDereferenceableAttr(Bytes);
continue;
}
case lltok::kw_dereferenceable_or_null: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
return true;
B.addDereferenceableOrNullAttr(Bytes);
continue;
}
case lltok::kw_align: {
MaybeAlign Alignment;
if (parseOptionalAlignment(Alignment))
return true;
B.addAlignmentAttr(Alignment);
continue;
}
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
case lltok::kw_noundef:
B.addAttribute(Attribute::NoUndef);
break;
case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break;
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
// error handling.
case lltok::kw_byval:
case lltok::kw_inalloca:
case lltok::kw_nest:
case lltok::kw_nocapture:
case lltok::kw_returned:
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
case lltok::kw_swiftasync:
case lltok::kw_immarg:
case lltok::kw_byref:
HaveError |=
error(Lex.getLoc(), "invalid use of parameter-only attribute");
break;
if (parseEnumAttribute(Attr, B, /* InAttrGroup */ false))
return true;
case lltok::kw_alignstack:
case lltok::kw_alwaysinline:
case lltok::kw_argmemonly:
case lltok::kw_builtin:
case lltok::kw_cold:
case lltok::kw_inlinehint:
case lltok::kw_jumptable:
case lltok::kw_minsize:
case lltok::kw_mustprogress:
case lltok::kw_naked:
case lltok::kw_nobuiltin:
case lltok::kw_noduplicate:
case lltok::kw_noimplicitfloat:
case lltok::kw_noinline:
case lltok::kw_nonlazybind:
case lltok::kw_nomerge:
case lltok::kw_noprofile:
case lltok::kw_noredzone:
case lltok::kw_noreturn:
case lltok::kw_nocf_check:
case lltok::kw_nounwind:
case lltok::kw_nosanitize_coverage:
case lltok::kw_optforfuzzing:
case lltok::kw_optnone:
case lltok::kw_optsize:
case lltok::kw_returns_twice:
case lltok::kw_sanitize_address:
case lltok::kw_sanitize_hwaddress:
case lltok::kw_sanitize_memtag:
case lltok::kw_sanitize_memory:
case lltok::kw_sanitize_thread:
case lltok::kw_speculative_load_hardening:
case lltok::kw_ssp:
case lltok::kw_sspreq:
case lltok::kw_sspstrong:
case lltok::kw_safestack:
case lltok::kw_shadowcallstack:
case lltok::kw_strictfp:
case lltok::kw_uwtable:
case lltok::kw_vscale_range:
HaveError |=
error(Lex.getLoc(), "invalid use of function-only attribute");
break;
case lltok::kw_readnone:
case lltok::kw_readonly:
HaveError |=
error(Lex.getLoc(), "invalid use of attribute on return type");
break;
case lltok::kw_preallocated:
HaveError |=
error(Lex.getLoc(),
"invalid use of parameter-only/call site-only attribute");
break;
}
Lex.Lex();
if (IsParam && !Attribute::canUseAsParamAttr(Attr))
HaveError |= error(Loc, "this attribute does not apply to parameters");
if (!IsParam && !Attribute::canUseAsRetAttr(Attr))
HaveError |= error(Loc, "this attribute does not apply to return values");
}
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:27: error: invalid use of parameter-only attribute on a function{{$}}
; CHECK: <stdin>:[[@LINE+1]]:33: error: expected type{{$}}
define void @test_byref() byref(4) {
ret void
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:8: error: invalid use of parameter-only attribute{{$}}
; CHECK: <stdin>:[[@LINE+1]]:14: error: expected '('{{$}}
define byref i8* @test_byref() {
ret void
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:8: error: invalid use of parameter-only attribute{{$}}
; CHECK: <stdin>:[[@LINE+1]]:14: error: expected '('{{$}}
define byref 8 i8* @test_byref() {
ret void
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:8: error: invalid use of parameter-only attribute{{$}}
; CHECK: <stdin>:[[@LINE+1]]:14: error: expected type{{$}}
define byref(8) i8* @test_byref() {
ret void
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:27: error: invalid use of parameter-only attribute on a function{{$}}
; CHECK: <stdin>:[[@LINE+1]]:33: error: expected '('{{$}}
define void @test_byref() byref {
ret void
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: <stdin>:[[@LINE+1]]:27: error: invalid use of parameter-only attribute on a function{{$}}
; CHECK: <stdin>:[[@LINE+1]]:32: error: expected '('{{$}}
define void @test_byref() byref=4 {
ret void
}

View File

@ -1,4 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
; CHECK: error: invalid use of parameter-only attribute on a function
; CHECK: error: this attribute does not apply to functions
declare void @llvm.immarg.func() immarg

View File

@ -1,4 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
; CHECK: error: invalid use of parameter-only attribute
; CHECK: error: this attribute does not apply to return values
declare immarg i32 @llvm.immarg.retattr(i32)

View File

@ -1,4 +1,4 @@
; RUN: not llvm-as -o /dev/null %s 2>&1 | FileCheck %s
; CHECK: error: invalid use of function-only attribute
; CHECK: error: this attribute does not apply to parameters
declare void @foo(i32 safestack %x)

View File

@ -1,4 +1,4 @@
; RUN: not llvm-as -o /dev/null %s 2>&1 | FileCheck %s
; CHECK: error: invalid use of function-only attribute
; CHECK: error: this attribute does not apply to return values
declare safestack void @foo()

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: [[@LINE+1]]:35: error: invalid use of function-only attribute
; CHECK: [[@LINE+1]]:35: error: this attribute does not apply to parameters
define void @test_mustprogress(i8 mustprogress %a) {
ret void
}

View File

@ -1,6 +1,6 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: [[@LINE+1]]:8: error: invalid use of function-only attribute
; CHECK: [[@LINE+1]]:8: error: this attribute does not apply to return values
define mustprogress void @test_mustprogress(i8 %a) {
ret void
}

View File

@ -37,4 +37,4 @@ _ZSt8_DestroyIP3LocILi3EEEvT_S3_.exit: ; preds = %2
declare void @llvm.assume(i1) #1
attributes #0 = { "target-cpu"="x86-64" }
attributes #1 = { willreturn readnone norecurse nocapture nofree }
attributes #1 = { willreturn readnone norecurse nofree }

View File

@ -1,4 +1,4 @@
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
; CHECK: invalid use of parameter-only attribute
; CHECK: this attribute does not apply to return values
declare swifterror void @c(i32** swifterror %a)