cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
431 lines
14 KiB
C++
431 lines
14 KiB
C++
//===- Class.cpp - Helper classes for Op C++ code emission --------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/TableGen/Class.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace mlir;
|
|
using namespace mlir::tblgen;
|
|
|
|
/// Returns space to be emitted after the given C++ `type`. return "" if the
|
|
/// ends with '&' or '*', or is empty, else returns " ".
|
|
static StringRef getSpaceAfterType(StringRef type) {
|
|
return (type.empty() || type.ends_with("&") || type.ends_with("*")) ? ""
|
|
: " ";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MethodParameter definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void MethodParameter::writeDeclTo(raw_indented_ostream &os) const {
|
|
if (optional)
|
|
os << "/*optional*/";
|
|
os << type << getSpaceAfterType(type) << name;
|
|
if (hasDefaultValue())
|
|
os << " = " << defaultValue;
|
|
}
|
|
|
|
void MethodParameter::writeDefTo(raw_indented_ostream &os) const {
|
|
if (optional)
|
|
os << "/*optional*/";
|
|
os << type << getSpaceAfterType(type) << name;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MethodParameters definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void MethodParameters::writeDeclTo(raw_indented_ostream &os) const {
|
|
llvm::interleaveComma(parameters, os,
|
|
[&os](auto ¶m) { param.writeDeclTo(os); });
|
|
}
|
|
void MethodParameters::writeDefTo(raw_indented_ostream &os) const {
|
|
llvm::interleaveComma(parameters, os,
|
|
[&os](auto ¶m) { param.writeDefTo(os); });
|
|
}
|
|
|
|
bool MethodParameters::subsumes(const MethodParameters &other) const {
|
|
// These parameters do not subsume the others if there are fewer parameters
|
|
// or their types do not match.
|
|
if (parameters.size() < other.parameters.size())
|
|
return false;
|
|
if (!std::equal(
|
|
other.parameters.begin(), other.parameters.end(), parameters.begin(),
|
|
[](auto &lhs, auto &rhs) { return lhs.getType() == rhs.getType(); }))
|
|
return false;
|
|
|
|
// If all the common parameters have the same type, we can elide the other
|
|
// method if this method has the same number of parameters as other or if the
|
|
// first paramater after the common parameters has a default value (and, as
|
|
// required by C++, subsequent parameters will have default values too).
|
|
return parameters.size() == other.parameters.size() ||
|
|
parameters[other.parameters.size()].hasDefaultValue();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MethodSignature definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool MethodSignature::makesRedundant(const MethodSignature &other) const {
|
|
return methodName == other.methodName &&
|
|
parameters.subsumes(other.parameters);
|
|
}
|
|
|
|
void MethodSignature::writeDeclTo(raw_indented_ostream &os) const {
|
|
os << returnType << getSpaceAfterType(returnType) << methodName << "(";
|
|
parameters.writeDeclTo(os);
|
|
os << ")";
|
|
}
|
|
|
|
void MethodSignature::writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const {
|
|
os << returnType << getSpaceAfterType(returnType) << namePrefix
|
|
<< (namePrefix.empty() ? "" : "::") << methodName << "(";
|
|
parameters.writeDefTo(os);
|
|
os << ")";
|
|
}
|
|
|
|
void MethodSignature::writeTemplateParamsTo(
|
|
mlir::raw_indented_ostream &os) const {
|
|
if (templateParams.empty())
|
|
return;
|
|
|
|
os << "template <";
|
|
llvm::interleaveComma(templateParams, os,
|
|
[&](StringRef param) { os << "typename " << param; });
|
|
os << ">\n";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MethodBody definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
MethodBody::MethodBody(bool declOnly)
|
|
: declOnly(declOnly), stringOs(body), os(stringOs) {}
|
|
|
|
void MethodBody::writeTo(raw_indented_ostream &os) const {
|
|
auto bodyRef = StringRef(body).ltrim('\n');
|
|
os << bodyRef;
|
|
if (bodyRef.empty())
|
|
return;
|
|
if (bodyRef.back() != '\n')
|
|
os << "\n";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Method definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void Method::writeDeclTo(raw_indented_ostream &os) const {
|
|
methodSignature.writeTemplateParamsTo(os);
|
|
if (deprecationMessage) {
|
|
os << "[[deprecated(\"";
|
|
os.write_escaped(*deprecationMessage);
|
|
os << "\")]]\n";
|
|
}
|
|
if (isStatic())
|
|
os << "static ";
|
|
if (properties & ConstexprValue)
|
|
os << "constexpr ";
|
|
methodSignature.writeDeclTo(os);
|
|
if (isConst())
|
|
os << " const";
|
|
if (!isInline()) {
|
|
os << ";\n";
|
|
return;
|
|
}
|
|
os << " {\n";
|
|
methodBody.writeTo(os);
|
|
os << "}\n\n";
|
|
}
|
|
|
|
void Method::writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const {
|
|
// The method has no definition to write if it is declaration only or inline.
|
|
if (properties & Declaration || isInline())
|
|
return;
|
|
|
|
methodSignature.writeDefTo(os, namePrefix);
|
|
if (isConst())
|
|
os << " const";
|
|
os << " {\n";
|
|
methodBody.writeTo(os);
|
|
os << "}\n\n";
|
|
}
|
|
|
|
bool Method::methodPropertiesAreCompatible(Properties properties) {
|
|
const bool isStatic = (properties & Method::Static);
|
|
const bool isConstructor = (properties & Method::Constructor);
|
|
// const bool isPrivate = (properties & Method::Private);
|
|
const bool isDeclaration = (properties & Method::Declaration);
|
|
const bool isInline = (properties & Method::Inline);
|
|
const bool isConstexprValue = (properties & Method::ConstexprValue);
|
|
const bool isConst = (properties & Method::Const);
|
|
|
|
// Note: assert to immediately fail and thus simplify debugging.
|
|
if (isStatic && isConstructor) {
|
|
assert(false && "constructor cannot be static");
|
|
return false;
|
|
}
|
|
if (isConstructor && isConst) { // albeit constexpr is fine
|
|
assert(false && "constructor cannot be const");
|
|
return false;
|
|
}
|
|
if (isDeclaration && isInline) {
|
|
assert(false &&
|
|
"declaration implies no definition and thus cannot be inline");
|
|
return false;
|
|
}
|
|
if (isDeclaration && isConstexprValue) {
|
|
assert(false &&
|
|
"declaration implies no definition and thus cannot be constexpr");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Constructor definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void Constructor::writeDeclTo(raw_indented_ostream &os) const {
|
|
methodSignature.writeTemplateParamsTo(os);
|
|
if (properties & ConstexprValue)
|
|
os << "constexpr ";
|
|
methodSignature.writeDeclTo(os);
|
|
if (!isInline()) {
|
|
os << ";\n\n";
|
|
return;
|
|
}
|
|
os << ' ';
|
|
if (!initializers.empty())
|
|
os << ": ";
|
|
llvm::interleaveComma(initializers, os,
|
|
[&](auto &initializer) { initializer.writeTo(os); });
|
|
if (!initializers.empty())
|
|
os << ' ';
|
|
os << "{";
|
|
methodBody.writeTo(os);
|
|
os << "}\n\n";
|
|
}
|
|
|
|
void Constructor::writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const {
|
|
// The method has no definition to write if it is declaration only or inline.
|
|
if (properties & Declaration || isInline())
|
|
return;
|
|
|
|
methodSignature.writeDefTo(os, namePrefix);
|
|
os << ' ';
|
|
if (!initializers.empty())
|
|
os << ": ";
|
|
llvm::interleaveComma(initializers, os,
|
|
[&](auto &initializer) { initializer.writeTo(os); });
|
|
if (!initializers.empty())
|
|
os << ' ';
|
|
os << "{";
|
|
methodBody.writeTo(os);
|
|
os << "}\n\n";
|
|
}
|
|
|
|
void Constructor::MemberInitializer::writeTo(raw_indented_ostream &os) const {
|
|
os << name << '(' << value << ')';
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Visibility definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace mlir {
|
|
namespace tblgen {
|
|
raw_ostream &operator<<(raw_ostream &os, Visibility visibility) {
|
|
switch (visibility) {
|
|
case Visibility::Public:
|
|
return os << "public";
|
|
case Visibility::Protected:
|
|
return os << "protected";
|
|
case Visibility::Private:
|
|
return os << "private";
|
|
}
|
|
return os;
|
|
}
|
|
} // namespace tblgen
|
|
} // namespace mlir
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ParentClass definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void ParentClass::writeTo(raw_indented_ostream &os) const {
|
|
os << visibility << ' ' << name;
|
|
if (!templateParams.empty()) {
|
|
auto scope = os.scope("<", ">", /*indent=*/false);
|
|
llvm::interleaveComma(templateParams, os,
|
|
[&](auto ¶m) { os << param; });
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// UsingDeclaration definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void UsingDeclaration::writeDeclTo(raw_indented_ostream &os) const {
|
|
if (!templateParams.empty()) {
|
|
os << "template <";
|
|
llvm::interleaveComma(templateParams, os, [&](StringRef paramName) {
|
|
os << "typename " << paramName;
|
|
});
|
|
os << ">\n";
|
|
}
|
|
os << "using " << name;
|
|
if (!value.empty())
|
|
os << " = " << value;
|
|
os << ";\n";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Field definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void Field::writeDeclTo(raw_indented_ostream &os) const {
|
|
os << type << ' ' << name << ";\n";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// VisibilityDeclaration definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void VisibilityDeclaration::writeDeclTo(raw_indented_ostream &os) const {
|
|
os.unindent();
|
|
os << visibility << ":\n";
|
|
os.indent();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ExtraClassDeclaration definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void ExtraClassDeclaration::writeDeclTo(raw_indented_ostream &os) const {
|
|
os.printReindented(extraClassDeclaration);
|
|
}
|
|
|
|
void ExtraClassDeclaration::writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const {
|
|
os.printReindented(extraClassDefinition);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Class definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ParentClass &Class::addParent(ParentClass parent) {
|
|
parents.push_back(std::move(parent));
|
|
return parents.back();
|
|
}
|
|
|
|
void Class::writeDeclTo(raw_indented_ostream &os) const {
|
|
if (!templateParams.empty()) {
|
|
os << "template <";
|
|
llvm::interleaveComma(templateParams, os,
|
|
[&](StringRef param) { os << "typename " << param; });
|
|
os << ">\n";
|
|
}
|
|
|
|
// Declare the class.
|
|
os << (isStruct ? "struct" : "class") << ' ' << className << ' ';
|
|
|
|
// Declare the parent classes, if any.
|
|
if (!parents.empty()) {
|
|
os << ": ";
|
|
llvm::interleaveComma(parents, os,
|
|
[&](auto &parent) { parent.writeTo(os); });
|
|
os << ' ';
|
|
}
|
|
auto classScope = os.scope("{\n", "};\n", /*indent=*/true);
|
|
|
|
// Print all the class declarations.
|
|
for (auto &decl : declarations)
|
|
decl->writeDeclTo(os);
|
|
}
|
|
|
|
void Class::writeDefTo(raw_indented_ostream &os) const {
|
|
// Print all the definitions.
|
|
for (auto &decl : declarations)
|
|
decl->writeDefTo(os, className);
|
|
}
|
|
|
|
void Class::finalize() {
|
|
// Sort the methods by public and private. Remove them from the pending list
|
|
// of methods.
|
|
SmallVector<std::unique_ptr<Method>> publicMethods, privateMethods;
|
|
for (auto &method : methods) {
|
|
if (method->isPrivate())
|
|
privateMethods.push_back(std::move(method));
|
|
else
|
|
publicMethods.push_back(std::move(method));
|
|
}
|
|
methods.clear();
|
|
|
|
// If the last visibility declaration wasn't `public`, add one that is. Then,
|
|
// declare the public methods.
|
|
if (!publicMethods.empty() && getLastVisibilityDecl() != Visibility::Public)
|
|
declare<VisibilityDeclaration>(Visibility::Public);
|
|
for (auto &method : publicMethods)
|
|
declarations.push_back(std::move(method));
|
|
|
|
// If the last visibility declaration wasn't `private`, add one that is. Then,
|
|
// declare the private methods.
|
|
if (!privateMethods.empty() && getLastVisibilityDecl() != Visibility::Private)
|
|
declare<VisibilityDeclaration>(Visibility::Private);
|
|
for (auto &method : privateMethods)
|
|
declarations.push_back(std::move(method));
|
|
|
|
// All fields added to the pending list are private and declared at the bottom
|
|
// of the class. If the last visibility declaration wasn't `private`, add one
|
|
// that is, then declare the fields.
|
|
if (!fields.empty() && getLastVisibilityDecl() != Visibility::Private)
|
|
declare<VisibilityDeclaration>(Visibility::Private);
|
|
for (auto &field : fields)
|
|
declare<Field>(std::move(field));
|
|
fields.clear();
|
|
}
|
|
|
|
Visibility Class::getLastVisibilityDecl() const {
|
|
auto reverseDecls = llvm::reverse(declarations);
|
|
auto it = llvm::find_if(reverseDecls, llvm::IsaPred<VisibilityDeclaration>);
|
|
return it == reverseDecls.end()
|
|
? (isStruct ? Visibility::Public : Visibility::Private)
|
|
: cast<VisibilityDeclaration>(**it).getVisibility();
|
|
}
|
|
|
|
Method *insertAndPruneMethods(std::vector<std::unique_ptr<Method>> &methods,
|
|
std::unique_ptr<Method> newMethod) {
|
|
if (llvm::any_of(methods, [&](auto &method) {
|
|
return method->makesRedundant(*newMethod);
|
|
}))
|
|
return nullptr;
|
|
|
|
llvm::erase_if(methods, [&](auto &method) {
|
|
return newMethod->makesRedundant(*method);
|
|
});
|
|
methods.push_back(std::move(newMethod));
|
|
return methods.back().get();
|
|
}
|
|
|
|
Method *Class::addMethodAndPrune(Method &&newMethod) {
|
|
return insertAndPruneMethods(methods,
|
|
std::make_unique<Method>(std::move(newMethod)));
|
|
}
|
|
|
|
Constructor *Class::addConstructorAndPrune(Constructor &&newCtor) {
|
|
return dyn_cast_or_null<Constructor>(insertAndPruneMethods(
|
|
methods, std::make_unique<Constructor>(std::move(newCtor))));
|
|
}
|