Add a C++11 and C2x spelling for the type safety attribute (argument_with_type_tag, pointer_with_type_tag, and type_tag_for_datatype) in the clang vendor namespace.

The TypeTagForDatatype attribute had custom parsing rules that previously prevented it from being supported with square bracket notation. The ArgumentWithTypeTag attribute previously had unnecessary custom parsing that could be handled declaratively.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@326052 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Aaron Ballman 2018-02-25 14:01:04 +00:00
parent 40332b100c
commit d925bc6aff
5 changed files with 60 additions and 23 deletions

View File

@ -2458,18 +2458,18 @@ def TestTypestate : InheritableAttr {
// Type safety attributes for `void *' pointers and type tags.
def ArgumentWithTypeTag : InheritableAttr {
let Spellings = [GNU<"argument_with_type_tag">,
GNU<"pointer_with_type_tag">];
let Spellings = [Clang<"argument_with_type_tag", 1>,
Clang<"pointer_with_type_tag", 1>];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Args = [IdentifierArgument<"ArgumentKind">,
UnsignedArgument<"ArgumentIdx">,
UnsignedArgument<"TypeTagIdx">,
BoolArgument<"IsPointer">];
let HasCustomParsing = 1;
BoolArgument<"IsPointer", /*opt*/0, /*fake*/1>];
let Documentation = [ArgumentWithTypeTagDocs, PointerWithTypeTagDocs];
}
def TypeTagForDatatype : InheritableAttr {
let Spellings = [GNU<"type_tag_for_datatype">];
let Spellings = [Clang<"type_tag_for_datatype", 1>];
let Args = [IdentifierArgument<"ArgumentKind">,
TypeArgument<"MatchingCType">,
BoolArgument<"LayoutCompatible">,

View File

@ -420,6 +420,10 @@ unsigned Parser::ParseClangAttributeArgs(
ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Syntax);
break;
case AttributeList::AT_TypeTagForDatatype:
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Syntax);
break;
}
return Attrs.getList() ? Attrs.getList()->getNumArgs() : 0;
}

View File

@ -4554,17 +4554,6 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
return;
}
if (!checkAttributeNumArgs(S, AL, 3))
return;
IdentifierInfo *ArgumentKind = AL.getArgAsIdent(0)->Ident;
if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type)
<< AL.getName() << ExpectedFunctionOrMethod;
return;
}
uint64_t ArgumentIdx;
if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1),
ArgumentIdx))
@ -4575,7 +4564,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
TypeTagIdx))
return;
bool IsPointer = (AL.getName()->getName() == "pointer_with_type_tag");
bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag";
if (IsPointer) {
// Ensure that buffer has a pointer type.
QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx);
@ -4585,10 +4574,9 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
}
D->addAttr(::new (S.Context)
ArgumentWithTypeTagAttr(AL.getRange(), S.Context, ArgumentKind,
ArgumentIdx, TypeTagIdx, IsPointer,
AL.getAttributeSpellingListIndex()));
D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(
AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx,
TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex()));
}
static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,

View File

@ -0,0 +1,45 @@
// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
struct A {};
typedef struct A *MPI_Datatype;
extern struct A datatype_wrong1 [[clang::type_tag_for_datatype]]; // expected-error {{'type_tag_for_datatype' attribute requires parameter 1 to be an identifier}}
extern struct A datatype_wrong2 [[clang::type_tag_for_datatype(mpi,1,2)]]; // expected-error {{expected a type}}
extern struct A datatype_wrong3 [[clang::type_tag_for_datatype(mpi,not_a_type)]]; // expected-error {{unknown type name 'not_a_type'}}
extern struct A datatype_wrong4 [[clang::type_tag_for_datatype(mpi,int,int)]]; // expected-error {{expected identifier}}
extern struct A datatype_wrong5 [[clang::type_tag_for_datatype(mpi,int,not_a_flag)]]; // expected-error {{invalid comparison flag 'not_a_flag'}}
extern struct A datatype_wrong6 [[clang::type_tag_for_datatype(mpi,int,layout_compatible,not_a_flag)]]; // expected-error {{invalid comparison flag 'not_a_flag'}}
extern struct A A_tag [[clang::type_tag_for_datatype(a,int)]];
extern struct A B_tag [[clang::type_tag_for_datatype(b,int)]];
static const int C_tag [[clang::type_tag_for_datatype(c,int)]] = 10;
static const int D_tag [[clang::type_tag_for_datatype(d,int)]] = 20;
[[clang::pointer_with_type_tag]] // expected-error {{'pointer_with_type_tag' attribute requires exactly 3 arguments}}
int wrong1(void *buf, MPI_Datatype datatype);
[[clang::pointer_with_type_tag(mpi,0,7)]] // expected-error {{attribute parameter 2 is out of bounds}}
int wrong2(void *buf, MPI_Datatype datatype);
[[clang::pointer_with_type_tag(mpi,3,7)]] // expected-error {{attribute parameter 2 is out of bounds}}
int wrong3(void *buf, MPI_Datatype datatype);
[[clang::pointer_with_type_tag(mpi,1,0)]] // expected-error {{attribute parameter 3 is out of bounds}}
int wrong4(void *buf, MPI_Datatype datatype);
[[clang::pointer_with_type_tag(mpi,1,3)]] // expected-error {{attribute parameter 3 is out of bounds}}
int wrong5(void *buf, MPI_Datatype datatype);
[[clang::pointer_with_type_tag(mpi,0x8000000000000001ULL,1)]] // expected-error {{attribute parameter 2 is out of bounds}}
int wrong6(void *buf, MPI_Datatype datatype);
[[clang::pointer_with_type_tag(a,1,2)]] void A_func(void *ptr, void *tag);
[[clang::pointer_with_type_tag(c,1,2)]] void C_func(void *ptr, int tag);

View File

@ -7,7 +7,7 @@ struct A {};
typedef struct A *MPI_Datatype;
int wrong1(void *buf, MPI_Datatype datatype)
__attribute__(( pointer_with_type_tag )); // expected-error {{'pointer_with_type_tag' attribute requires parameter 1 to be an identifier}}
__attribute__(( pointer_with_type_tag )); // expected-error {{'pointer_with_type_tag' attribute requires exactly 3 arguments}}
int wrong2(void *buf, MPI_Datatype datatype)
__attribute__(( pointer_with_type_tag(mpi,0,7) )); // expected-error {{attribute parameter 2 is out of bounds}}
@ -32,7 +32,7 @@ int wrong7(void *buf, MPI_Datatype datatype)
int wrong8(void *buf, MPI_Datatype datatype)
__attribute__(( pointer_with_type_tag(mpi,1,x) )); // expected-error {{attribute requires parameter 3 to be an integer constant}}
int wrong9 __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{attribute only applies to functions and methods}}
int wrong9 __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to non-K&R-style functions}}
int wrong10(double buf, MPI_Datatype type)
__attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to pointer arguments}}