[Verifier] Improve incompatible attribute type check
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 14 Jul 2021 18:58:52 +0000 (20:58 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 14 Jul 2021 19:02:10 +0000 (21:02 +0200)
A couple of attributes had explicit checks for incompatibility
with pointer types. However, this is already handled generically
by the typeIncompatible() check. We can drop these after adding
SwiftError to typeIncompatible().

However, the previous implementation of the check prints out all
attributes that are incompatible with a given type, even though
those attributes aren't actually used. This has the annoying
result that the error message changes every time a new attribute
is added to the list. Improve this by explicitly finding which
attribute isn't compatible and printing just that.

llvm/lib/IR/Attributes.cpp
llvm/lib/IR/Verifier.cpp
llvm/test/Verifier/align.ll
llvm/test/Verifier/byref.ll
llvm/test/Verifier/byval-1.ll
llvm/test/Verifier/inalloca1.ll
llvm/test/Verifier/noundef.ll
llvm/test/Verifier/preallocated-invalid.ll
llvm/test/Verifier/sret.ll
llvm/test/Verifier/swifterror.ll

index beb8a24..31cef09 100644 (file)
@@ -1923,11 +1923,12 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) {
         .addAttribute(Attribute::NoAlias)
         .addAttribute(Attribute::NoCapture)
         .addAttribute(Attribute::NonNull)
+        .addAttribute(Attribute::ReadNone)
+        .addAttribute(Attribute::ReadOnly)
+        .addAttribute(Attribute::SwiftError)
         .addAlignmentAttr(1)             // the int here is ignored
         .addDereferenceableAttr(1)       // the int here is ignored
         .addDereferenceableOrNullAttr(1) // the int here is ignored
-        .addAttribute(Attribute::ReadNone)
-        .addAttribute(Attribute::ReadOnly)
         .addPreallocatedAttr(Ty)
         .addInAllocaAttr(Ty)
         .addByValAttr(Ty)
index bd7bcf3..442857e 100644 (file)
@@ -1758,10 +1758,14 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
          V);
 
   AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
-  Assert(!AttrBuilder(Attrs).overlaps(IncompatibleAttrs),
-         "Wrong types for attribute: " +
-             AttributeSet::get(Context, IncompatibleAttrs).getAsString(),
-         V);
+  for (Attribute Attr : Attrs) {
+    if (!Attr.isStringAttribute() &&
+        IncompatibleAttrs.contains(Attr.getKindAsEnum())) {
+      CheckFailed("Attribute '" + Attr.getAsString() +
+                  "' applied to incompatible type!", V);
+      return;
+    }
+  }
 
   if (PointerType *PTy = dyn_cast<PointerType>(Ty)) {
     if (Attrs.hasAttribute(Attribute::ByVal)) {
@@ -1810,17 +1814,6 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
                "Attribute 'inalloca' type does not match parameter!", V);
       }
     }
-  } else {
-    Assert(!Attrs.hasAttribute(Attribute::ByVal),
-           "Attribute 'byval' only applies to parameters with pointer type!",
-           V);
-    Assert(!Attrs.hasAttribute(Attribute::ByRef),
-           "Attribute 'byref' only applies to parameters with pointer type!",
-           V);
-    Assert(!Attrs.hasAttribute(Attribute::SwiftError),
-           "Attribute 'swifterror' only applies to parameters "
-           "with pointer type!",
-           V);
   }
 }
 
index 1f5c8da..76379eb 100644 (file)
@@ -1,12 +1,12 @@
 ; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
 
-; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Attribute 'align 4' applied to incompatible type!
 ; CHECK-NEXT: @align_non_pointer1
 define void @align_non_pointer1(i32 align 4 %a) {
   ret void
 }
 
-; CHECK: Wrong types for attribute: nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) inalloca(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Attribute 'align 4' applied to incompatible type!
 ; CHECK-NEXT: @align_non_pointer2
 define align 4 void @align_non_pointer2(i32 %a) {
   ret void
index 6cd66eb..6a8df2d 100644 (file)
@@ -56,7 +56,7 @@ define void @byref_nest(i32* byref(i32) nest) {
   ret void
 }
 
-; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Attribute 'byref(i32)' applied to incompatible type!
 ; CHECK-NEXT: void (i32)* @byref_non_pointer
 define void @byref_non_pointer(i32 byref(i32)) {
   ret void
index 6344371..6d0c46a 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
 
-; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Attribute 'byval(i32)' applied to incompatible type!
 ; CHECK-NEXT: void (i32)* @h
 declare void @h(i32 byval(i32) %num)
index db911b2..af31f89 100644 (file)
@@ -27,8 +27,8 @@ define void @inalloca_mismatched_pointee_type0(i32* inalloca(i8)) {
   ret void
 }
 
-; CHECK: Wrong types for attribute:
+; CHECK: Attribute 'inalloca(i8)' applied to incompatible type!
 ; CHECK-NEXT: void (i8)* @inalloca_not_pointer
-define void @inalloca_not_pointer(i8 byref(i8)) {
+define void @inalloca_not_pointer(i8 inalloca(i8)) {
   ret void
 }
index 2ece2dd..9ee5a18 100644 (file)
@@ -1,6 +1,6 @@
 ; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
 
-; CHECK: Wrong types for attribute: nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) inalloca(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Attribute 'noundef' applied to incompatible type!
 ; CHECK-NEXT: @noundef_void
 define noundef void @noundef_void() {
   ret void
index 392937f..b0aa83e 100644 (file)
@@ -145,6 +145,6 @@ define void @teardown_token_not_from_setup() {
     ret void
 }
 
-; CHECK: Wrong types for attribute:
+; CHECK: Attribute 'preallocated(i32)' applied to incompatible type!
 ; CHECK-NEXT: void (i32)* @not_pointer
 declare void @not_pointer(i32 preallocated(i32))
index 54e0d5b..6b4097a 100644 (file)
@@ -6,6 +6,6 @@ declare void @a(i32* sret(i32) %a, i32* sret(i32) %b)
 declare void @b(i32* %a, i32* %b, i32* sret(i32) %c)
 ; CHECK: Attribute 'sret' is not on first or second parameter!
 
-; CHECK: Wrong types for attribute:
+; CHECK: Attribute 'sret(i32)' applied to incompatible type!
 ; CHECK-NEXT: void (i32)* @not_ptr
 declare void @not_ptr(i32 sret(i32) %x)
index d8eacf5..78c26d7 100644 (file)
@@ -24,7 +24,7 @@ entry:
 ; CHECK: Cannot have multiple 'swifterror' parameters!
 declare void @a(i32** swifterror %a, i32** swifterror %b)
 
-; CHECK: Attribute 'swifterror' only applies to parameters with pointer type!
+; CHECK: Attribute 'swifterror' applied to incompatible type!
 declare void @b(i32 swifterror %a)
 
 ; CHECK: Attribute 'swifterror' only applies to parameters with pointer to pointer type!