r367040 - Add lifetime categories attributes
Matthias Gehre via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 25 10:50:51 PDT 2019
Author: mgehre
Date: Thu Jul 25 10:50:51 2019
New Revision: 367040
URL: http://llvm.org/viewvc/llvm-project?rev=367040&view=rev
Log:
Add lifetime categories attributes
Summary:
This is the first part of work announced in
"[RFC] Adding lifetime analysis to clang" [0],
i.e. the addition of the [[gsl::Owner(T)]] and
[[gsl::Pointer(T)]] attributes, which
will enable user-defined types to participate in
the lifetime analysis (which will be part of the
next PR).
The type `T` here is called "DerefType" in the paper,
and denotes the type that an Owner owns and a Pointer
points to. E.g. `std::vector<int>` should be annotated
with `[[gsl::Owner(int)]]` and
a `std::vector<int>::iterator` with `[[gsl::Pointer(int)]]`.
[0] http://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html
Reviewers: gribozavr
Subscribers: xazax.hun, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63954
Added:
cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp
Modified:
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/AttrDocs.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/AST/ast-dump-attr.cpp
cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
cfe/trunk/test/SemaOpenCL/invalid-kernel-attrs.cl
cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jul 25 10:50:51 2019
@@ -2796,6 +2796,20 @@ def TypeTagForDatatype : InheritableAttr
let Documentation = [TypeTagForDatatypeDocs];
}
+def Owner : InheritableAttr {
+ let Spellings = [CXX11<"gsl", "Owner">];
+ let Subjects = SubjectList<[Struct]>;
+ let Args = [TypeArgument<"DerefType", /*opt=*/1>];
+ let Documentation = [LifetimeOwnerDocs];
+}
+
+def Pointer : InheritableAttr {
+ let Spellings = [CXX11<"gsl", "Pointer">];
+ let Subjects = SubjectList<[Struct]>;
+ let Args = [TypeArgument<"DerefType", /*opt=*/1>];
+ let Documentation = [LifetimePointerDocs];
+}
+
// Microsoft-related attributes
def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Thu Jul 25 10:50:51 2019
@@ -4230,3 +4230,71 @@ not initialized on device side. It has i
the initializer on host side.
}];
}
+
+def LifetimeOwnerDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{
+.. Note:: This attribute is experimental and its effect on analysis is subject to change in
+ a future version of clang.
+
+The attribute ``[[gsl::Owner(T)]]`` applies to structs and classes that own an
+object of type ``T``:
+
+.. code-block:: c++
+
+ class [[gsl::Owner(int)]] IntOwner {
+ private:
+ int value;
+ public:
+ int *getInt() { return &value; }
+ };
+
+The argument ``T`` is optional and currently ignored.
+This attribute may be used by analysis tools and has no effect on code
+generation.
+
+See Pointer_ for an example.
+}];
+}
+
+def LifetimePointerDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{
+.. Note:: This attribute is experimental and its effect on analysis is subject to change in
+ a future version of clang.
+
+The attribute ``[[gsl::Pointer(T)]]`` applies to structs and classes that behave
+like pointers to an object of type ``T``:
+
+.. code-block:: c++
+
+ class [[gsl::Pointer(int)]] IntPointer {
+ private:
+ int *valuePointer;
+ public:
+ int *getInt() { return &valuePointer; }
+ };
+
+The argument ``T`` is optional and currently ignored.
+This attribute may be used by analysis tools and has no effect on code
+generation.
+
+Example:
+When constructing an instance of a class annotated like this (a Pointer) from
+an instance of a class annotated with ``[[gsl::Owner]]`` (an Owner),
+then the analysis will consider the Pointer to point inside the Owner.
+When the Owner's lifetime ends, it will consider the Pointer to be dangling.
+
+.. code-block:: c++
+
+ int f() {
+ IntPointer P;
+ if (true) {
+ IntOwner O(7);
+ P = IntPointer(O); // P "points into" O
+ } // P is dangling
+ return P.get(); // error: Using a dangling Pointer.
+ }
+
+}];
+}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 25 10:50:51 2019
@@ -2519,6 +2519,9 @@ def err_nsobject_attribute : Error<
"'NSObject' attribute is for pointer types only">;
def err_attributes_are_not_compatible : Error<
"%0 and %1 attributes are not compatible">;
+def err_attribute_invalid_argument : Error<
+ "%select{'void'|a reference type|an array type|a non-vector or "
+ "non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
def err_attribute_wrong_number_arguments : Error<
"%0 attribute %plural{0:takes no arguments|1:takes one argument|"
":requires exactly %1 arguments}1">;
@@ -2567,8 +2570,6 @@ def err_attribute_argument_out_of_range
def err_init_priority_object_attr : Error<
"can only use 'init_priority' attribute on file-scope definitions "
"of objects of class type">;
-def err_attribute_argument_vec_type_hint : Error<
- "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
def err_attribute_argument_out_of_bounds : Error<
"%0 attribute parameter %1 is out of bounds">;
def err_attribute_only_once_per_parameter : Error<
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Jul 25 10:50:51 2019
@@ -335,6 +335,7 @@ unsigned Parser::ParseAttributeArgsCommo
ConsumeParen();
bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName);
+ bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName);
// Interpret "kw_this" as an identifier if the attributed requests it.
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
@@ -360,6 +361,7 @@ unsigned Parser::ParseAttributeArgsCommo
ArgExprs.push_back(ParseIdentifierLoc());
}
+ ParsedType TheParsedType;
if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) {
// Eat the comma.
if (!ArgExprs.empty())
@@ -372,8 +374,17 @@ unsigned Parser::ParseAttributeArgsCommo
Tok.setKind(tok::identifier);
ExprResult ArgExpr;
- if (Tok.is(tok::identifier) &&
- attributeHasVariadicIdentifierArg(*AttrName)) {
+ if (AttributeIsTypeArgAttr) {
+ TypeResult T = ParseTypeName();
+ if (T.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return 0;
+ }
+ if (T.isUsable())
+ TheParsedType = T.get();
+ break; // FIXME: Multiple type arguments are not implemented.
+ } else if (Tok.is(tok::identifier) &&
+ attributeHasVariadicIdentifierArg(*AttrName)) {
ArgExprs.push_back(ParseIdentifierLoc());
} else {
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
@@ -397,14 +408,20 @@ unsigned Parser::ParseAttributeArgsCommo
SourceLocation RParen = Tok.getLocation();
if (!ExpectAndConsume(tok::r_paren)) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
+
+ if (AttributeIsTypeArgAttr && !TheParsedType.get().isNull()) {
+ Attrs.addNewTypeAttr(AttrName, SourceRange(AttrNameLoc, RParen),
+ ScopeName, ScopeLoc, TheParsedType, Syntax);
+ } else {
+ Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
+ ArgExprs.data(), ArgExprs.size(), Syntax);
+ }
}
if (EndLoc)
*EndLoc = RParen;
- return static_cast<unsigned>(ArgExprs.size());
+ return static_cast<unsigned>(ArgExprs.size() + !TheParsedType.get().isNull());
}
/// Parse the arguments to a parameterized GNU attribute or
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jul 25 10:50:51 2019
@@ -2954,8 +2954,7 @@ static void handleVecTypeHint(Sema &S, D
if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
(ParmType->isBooleanType() ||
!ParmType->isIntegralType(S.getASTContext()))) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_vec_type_hint)
- << ParmType;
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL;
return;
}
@@ -4555,6 +4554,67 @@ static void handleSuppressAttr(Sema &S,
DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex()));
}
+static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ TypeSourceInfo *DerefTypeLoc = nullptr;
+ QualType ParmType;
+ if (AL.hasParsedType()) {
+ ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
+
+ unsigned SelectIdx = ~0U;
+ if (ParmType->isVoidType())
+ SelectIdx = 0;
+ else if (ParmType->isReferenceType())
+ SelectIdx = 1;
+ else if (ParmType->isArrayType())
+ SelectIdx = 2;
+
+ if (SelectIdx != ~0U) {
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
+ << SelectIdx << AL;
+ return;
+ }
+ }
+
+ // To check if earlier decl attributes do not conflict the newly parsed ones
+ // we always add (and check) the attribute to the cannonical decl.
+ D = D->getCanonicalDecl();
+ if (AL.getKind() == ParsedAttr::AT_Owner) {
+ if (checkAttrMutualExclusion<PointerAttr>(S, D, AL))
+ return;
+ if (const auto *OAttr = D->getAttr<OwnerAttr>()) {
+ const Type *ExistingDerefType = OAttr->getDerefTypeLoc()
+ ? OAttr->getDerefType().getTypePtr()
+ : nullptr;
+ if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << OAttr;
+ S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute);
+ }
+ return;
+ }
+ D->addAttr(::new (S.Context)
+ OwnerAttr(AL.getRange(), S.Context, DerefTypeLoc,
+ AL.getAttributeSpellingListIndex()));
+ } else {
+ if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL))
+ return;
+ if (const auto *PAttr = D->getAttr<PointerAttr>()) {
+ const Type *ExistingDerefType = PAttr->getDerefTypeLoc()
+ ? PAttr->getDerefType().getTypePtr()
+ : nullptr;
+ if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << PAttr;
+ S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute);
+ }
+ return;
+ }
+ D->addAttr(::new (S.Context)
+ PointerAttr(AL.getRange(), S.Context, DerefTypeLoc,
+ AL.getAttributeSpellingListIndex()));
+ }
+}
+
bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
const FunctionDecl *FD) {
if (Attrs.isInvalid())
@@ -7158,6 +7218,10 @@ static void ProcessDeclAttribute(Sema &S
case ParsedAttr::AT_Suppress:
handleSuppressAttr(S, D, AL);
break;
+ case ParsedAttr::AT_Owner:
+ case ParsedAttr::AT_Pointer:
+ handleLifetimeCategoryAttr(S, D, AL);
+ break;
case ParsedAttr::AT_OpenCLKernel:
handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL);
break;
Modified: cfe/trunk/test/AST/ast-dump-attr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-attr.cpp?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/test/AST/ast-dump-attr.cpp (original)
+++ cfe/trunk/test/AST/ast-dump-attr.cpp Thu Jul 25 10:50:51 2019
@@ -211,6 +211,23 @@ namespace TestSuppress {
}
}
+namespace TestLifetimeCategories {
+class [[gsl::Owner(int)]] AOwner{};
+// CHECK: CXXRecordDecl{{.*}} class AOwner
+// CHECK: OwnerAttr {{.*}} int
+class [[gsl::Pointer(int)]] APointer{};
+// CHECK: CXXRecordDecl{{.*}} class APointer
+// CHECK: PointerAttr {{.*}} int
+
+class [[gsl::Pointer]] PointerWithoutArgument{};
+// CHECK: CXXRecordDecl{{.*}} class PointerWithoutArgument
+// CHECK: PointerAttr
+
+class [[gsl::Owner]] OwnerWithoutArgument{};
+// CHECK: CXXRecordDecl{{.*}} class OwnerWithoutArgument
+// CHECK: OwnerAttr
+} // namespace TestLifetimeCategories
+
// Verify the order of attributes in the Ast. It must reflect the order
// in the parsed source.
int mergeAttrTest() __attribute__((deprecated)) __attribute__((warn_unused_result));
Modified: cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test (original)
+++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test Thu Jul 25 10:50:51 2019
@@ -117,8 +117,10 @@
// CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
// CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record_not_is_union)
// CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (SubjectMatchRule_record_not_is_union)
// CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
// CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
// CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
Added: cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp?rev=367040&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp (added)
+++ cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp Thu Jul 25 10:50:51 2019
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 -verify -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+int [[gsl::Owner]] i;
+// expected-error at -1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error at -1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning at -1 {{'Owner' attribute only applies to structs}}
+
+union [[gsl::Owner(int)]] Union{};
+// expected-warning at -1 {{'Owner' attribute only applies to structs}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error at -1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error at -1 {{expected a type}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error at -1 {{expected a type}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error at -1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note at -2 {{conflicting attribute is here}}
+// CHECK: CXXRecordDecl {{.*}} BothOwnerPointer
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error at -1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error at -1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+// CHECK: CXXRecordDecl {{.*}} AddConflictLater
+// CHECK: PointerAttr {{.*}} int
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error at -1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note at -5 {{conflicting attribute is here}}
+// CHECK: CXXRecordDecl {{.*}} AddConflictLater
+// CHECK: PointerAttr {{.*}} Inherited int
+
+class [[gsl::Owner(int)]] AddConflictLater2{};
+// CHECK: CXXRecordDecl {{.*}} AddConflictLater2
+// CHECK: OwnerAttr {{.*}} int
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error at -1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note at -5 {{conflicting attribute is here}}
+// CHECK: CXXRecordDecl {{.*}} AddConflictLater
+// CHECK: OwnerAttr {{.*}} Inherited int
+
+class [[gsl::Owner()]] [[gsl::Owner(int)]] WithAndWithoutParameter{};
+// expected-error at -1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note at -2 {{conflicting attribute is here}}
+// CHECK: CXXRecordDecl {{.*}} WithAndWithoutParameter
+// CHECK: OwnerAttr
+
+class [[gsl::Owner(int &)]] ReferenceType{};
+// expected-error at -1 {{a reference type is an invalid argument to attribute 'Owner'}}
+
+class [[gsl::Pointer(int[])]] ArrayType{};
+// expected-error at -1 {{an array type is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} OwnerMissingParameter
+// CHECK: OwnerAttr
+
+class [[gsl::Pointer]] PointerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} PointerMissingParameter
+// CHECK: PointerAttr
+
+class [[gsl::Owner()]] OwnerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} OwnerWithEmptyParameterList
+// CHECK: OwnerAttr {{.*}}
+
+class [[gsl::Pointer()]] PointerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} PointerWithEmptyParameterList
+// CHECK: PointerAttr {{.*}}
+
+struct [[gsl::Owner(int)]] AnOwner{};
+// CHECK: CXXRecordDecl {{.*}} AnOwner
+// CHECK: OwnerAttr {{.*}} int
+
+struct S;
+class [[gsl::Pointer(S)]] APointer{};
+// CHECK: CXXRecordDecl {{.*}} APointer
+// CHECK: PointerAttr {{.*}} S
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+// CHECK: CXXRecordDecl {{.*}} DuplicateOwner
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+// CHECK: CXXRecordDecl {{.*}} DuplicatePointer
+// CHECK: PointerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+// CHECK: CXXRecordDecl {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater;
+// CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
Modified: cfe/trunk/test/SemaOpenCL/invalid-kernel-attrs.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/invalid-kernel-attrs.cl?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/invalid-kernel-attrs.cl (original)
+++ cfe/trunk/test/SemaOpenCL/invalid-kernel-attrs.cl Thu Jul 25 10:50:51 2019
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify %s
kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{'vec_type_hint' attribute takes one argument}}
kernel __attribute__((vec_type_hint(not_type))) void kernel2() {} //expected-error{{unknown type name 'not_type'}}
-kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{invalid attribute argument 'void' - expecting a vector or vectorizable scalar type}}
+kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{a non-vector or non-vectorizable scalar type is an invalid argument to attribute 'vec_type_hint'}}
-kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{invalid attribute argument 'bool' - expecting a vector or vectorizable scalar type}}
+kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{a non-vector or non-vectorizable scalar type is an invalid argument to attribute 'vec_type_hint'}}
kernel __attribute__((vec_type_hint(int))) __attribute__((vec_type_hint(float))) void kernel5() {} //expected-warning{{attribute 'vec_type_hint' is already applied with different parameters}}
Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=367040&r1=367039&r2=367040&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Thu Jul 25 10:50:51 2019
@@ -303,6 +303,8 @@ namespace {
std::string getIsOmitted() const override {
if (type == "IdentifierInfo *")
return "!get" + getUpperName().str() + "()";
+ if (type == "TypeSourceInfo *")
+ return "!get" + getUpperName().str() + "Loc()";
if (type == "ParamIdx")
return "!get" + getUpperName().str() + "().isValid()";
return "false";
@@ -336,6 +338,8 @@ namespace {
<< " OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
} else if (type == "TypeSourceInfo *") {
+ if (isOptional())
+ OS << " if (SA->get" << getUpperName() << "Loc())";
OS << " OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
} else if (type == "bool") {
More information about the cfe-commits
mailing list