Attributes don't know their parent Context, adding this would make Attribute larger. Instead, we add hasParentContext that answers whether this Attribute belongs to a particular LLVMContext by checking for itself inside the context's FoldingSet. Same with AttributeSet and AttributeList. The Verifier checks them with the Module context.
Differential Revision: https://reviews.llvm.org/D99362
/// is, presumably, for writing out the mnemonics for the assembly writer.
std::string getAsString(bool InAttrGrp = false) const;
+ /// Return true if this attribute belongs to the LLVMContext.
+ bool hasParentContext(LLVMContext &C) const;
+
/// Equality and non-equality operators.
bool operator==(Attribute A) const { return pImpl == A.pImpl; }
bool operator!=(Attribute A) const { return pImpl != A.pImpl; }
std::pair<unsigned, unsigned> getVScaleRangeArgs() const;
std::string getAsString(bool InAttrGrp = false) const;
+ /// Return true if this attribute set belongs to the LLVMContext.
+ bool hasParentContext(LLVMContext &C) const;
+
using iterator = const Attribute *;
iterator begin() const;
/// Return the attributes at the index as a string.
std::string getAsString(unsigned Index, bool InAttrGrp = false) const;
+ /// Return true if this attribute list belongs to the LLVMContext.
+ bool hasParentContext(LLVMContext &C) const;
+
//===--------------------------------------------------------------------===//
// AttributeList Introspection
//===--------------------------------------------------------------------===//
/// Return true if there are no attributes.
bool isEmpty() const { return pImpl == nullptr; }
+ void print(raw_ostream &O) const;
+
void dump() const;
};
llvm_unreachable("Unknown attribute");
}
+bool Attribute::hasParentContext(LLVMContext &C) const {
+ assert(isValid() && "invalid Attribute doesn't refer to any context");
+ FoldingSetNodeID ID;
+ pImpl->Profile(ID);
+ void *Unused;
+ return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, Unused) == pImpl;
+}
+
bool Attribute::operator<(Attribute A) const {
if (!pImpl && !A.pImpl) return false;
if (!pImpl) return true;
return SetNode ? SetNode->getAsString(InAttrGrp) : "";
}
+bool AttributeSet::hasParentContext(LLVMContext &C) const {
+ assert(hasAttributes() && "empty AttributeSet doesn't refer to any context");
+ FoldingSetNodeID ID;
+ SetNode->Profile(ID);
+ void *Unused;
+ return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, Unused) == SetNode;
+}
+
AttributeSet::iterator AttributeSet::begin() const {
return SetNode ? SetNode->begin() : nullptr;
}
return pImpl->begin()[Index];
}
+bool AttributeList::hasParentContext(LLVMContext &C) const {
+ assert(!isEmpty() && "an empty attribute list has no parent context");
+ FoldingSetNodeID ID;
+ pImpl->Profile(ID);
+ void *Unused;
+ return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, Unused) == pImpl;
+}
+
AttributeList::iterator AttributeList::begin() const {
return pImpl ? pImpl->begin() : nullptr;
}
return pImpl ? pImpl->NumAttrSets : 0;
}
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_DUMP_METHOD void AttributeList::dump() const {
- dbgs() << "PAL[\n";
+void AttributeList::print(raw_ostream &O) const {
+ O << "PAL[\n";
for (unsigned i = index_begin(), e = index_end(); i != e; ++i) {
if (getAttributes(i).hasAttributes())
- dbgs() << " { " << i << " => " << getAsString(i) << " }\n";
+ O << " { " << i << " => " << getAsString(i) << " }\n";
}
- dbgs() << "]\n";
+ O << "]\n";
}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); }
#endif
//===----------------------------------------------------------------------===//
void Write(const unsigned i) { *OS << i << '\n'; }
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void Write(const Attribute *A) {
+ if (!A)
+ return;
+ *OS << A->getAsString() << '\n';
+ }
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void Write(const AttributeSet *AS) {
+ if (!AS)
+ return;
+ *OS << AS->getAsString() << '\n';
+ }
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ void Write(const AttributeList *AL) {
+ if (!AL)
+ return;
+ AL->print(*OS);
+ }
+
template <typename T> void Write(ArrayRef<T> Vs) {
for (const T &V : Vs)
Write(V);
if (Attrs.isEmpty())
return;
+ Assert(Attrs.hasParentContext(Context),
+ "Attribute list does not match Module context!", &Attrs);
+ for (const auto &AttrSet : Attrs) {
+ Assert(!AttrSet.hasAttributes() || AttrSet.hasParentContext(Context),
+ "Attribute set does not match Module context!", &AttrSet);
+ for (const auto &A : AttrSet) {
+ Assert(A.hasParentContext(Context),
+ "Attribute does not match Module context!", &A);
+ }
+ }
+
bool SawNest = false;
bool SawReturned = false;
bool SawSRet = false;
EXPECT_EQ(A.getAsString(), "byval(i32)");
}
+TEST(Attributes, HasParentContext) {
+ LLVMContext C1, C2;
+
+ {
+ Attribute Attr1 = Attribute::get(C1, Attribute::AlwaysInline);
+ Attribute Attr2 = Attribute::get(C2, Attribute::AlwaysInline);
+ EXPECT_TRUE(Attr1.hasParentContext(C1));
+ EXPECT_FALSE(Attr1.hasParentContext(C2));
+ EXPECT_FALSE(Attr2.hasParentContext(C1));
+ EXPECT_TRUE(Attr2.hasParentContext(C2));
+ }
+
+ {
+ AttributeSet AS1 = AttributeSet::get(
+ C1, makeArrayRef(Attribute::get(C1, Attribute::NoReturn)));
+ AttributeSet AS2 = AttributeSet::get(
+ C2, makeArrayRef(Attribute::get(C2, Attribute::NoReturn)));
+ EXPECT_TRUE(AS1.hasParentContext(C1));
+ EXPECT_FALSE(AS1.hasParentContext(C2));
+ EXPECT_FALSE(AS2.hasParentContext(C1));
+ EXPECT_TRUE(AS2.hasParentContext(C2));
+ }
+
+ {
+ AttributeList AL1 = AttributeList::get(C1, 1, Attribute::ZExt);
+ AttributeList AL2 = AttributeList::get(C2, 1, Attribute::ZExt);
+ EXPECT_TRUE(AL1.hasParentContext(C1));
+ EXPECT_FALSE(AL1.hasParentContext(C2));
+ EXPECT_FALSE(AL2.hasParentContext(C1));
+ EXPECT_TRUE(AL2.hasParentContext(C2));
+ }
+}
+
} // end anonymous namespace
.startswith("MDNode context does not match Module context!"));
}
+TEST(VerifierTest, AttributesWrongContext) {
+ LLVMContext C1, C2;
+ Module M1("M", C1);
+ FunctionType *FTy1 =
+ FunctionType::get(Type::getVoidTy(C1), /*isVarArg=*/false);
+ Function *F1 = Function::Create(FTy1, Function::ExternalLinkage, "foo", M1);
+ F1->setDoesNotReturn();
+
+ Module M2("M", C2);
+ FunctionType *FTy2 =
+ FunctionType::get(Type::getVoidTy(C2), /*isVarArg=*/false);
+ Function *F2 = Function::Create(FTy2, Function::ExternalLinkage, "foo", M2);
+ F2->copyAttributesFrom(F1);
+
+ EXPECT_TRUE(verifyFunction(*F2));
+}
+
} // end anonymous namespace
} // end namespace llvm