// 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">,
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;
}
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))
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);
}
}
- 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,
--- /dev/null
+// 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);
+
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}}
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}}