From d925bc6affe1ed96737cc016f0dc53cdd89bee5b Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Sun, 25 Feb 2018 14:01:04 +0000 Subject: [PATCH] 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 --- include/clang/Basic/Attr.td | 10 ++++---- lib/Parse/ParseDecl.cpp | 4 ++++ lib/Sema/SemaDeclAttr.cpp | 20 ++++------------ test/Sema/attr-type-safety.c | 45 ++++++++++++++++++++++++++++++++++++ test/Sema/warn-type-safety.c | 4 ++-- 5 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 test/Sema/attr-type-safety.c diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 339fbb8120..aa3cc6944b 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -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">, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d79ca8a0b2..491ad31e17 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 458c31881d..4247b32a67 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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, diff --git a/test/Sema/attr-type-safety.c b/test/Sema/attr-type-safety.c new file mode 100644 index 0000000000..d7dab5d307 --- /dev/null +++ b/test/Sema/attr-type-safety.c @@ -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); + diff --git a/test/Sema/warn-type-safety.c b/test/Sema/warn-type-safety.c index 04313865a8..36fb47e254 100644 --- a/test/Sema/warn-type-safety.c +++ b/test/Sema/warn-type-safety.c @@ -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}} -- 2.40.0