Revert "Swift: use C++20 constraints and concepts to simplify code"

This commit is contained in:
Paolo Tranquilli
2023-08-21 17:40:15 +02:00
committed by GitHub
parent 6d85d0d0f7
commit 1daedd9fb6
7 changed files with 226 additions and 121 deletions

View File

@@ -6,7 +6,7 @@ namespace codeql {
{{#tags}} {{#tags}}
// {{id}} // {{id}}
struct {{name}}Tag {{#has_bases}}: {{#bases}}{{^first}}, {{/first}}virtual {{base}}Tag{{/bases}} {{/has_bases}}{ struct {{name}}Tag {{#has_bases}}: {{#bases}}{{^first}}, {{/first}}{{base}}Tag{{/bases}} {{/has_bases}}{
static constexpr const char* prefix = "{{name}}"; static constexpr const char* prefix = "{{name}}";
}; };
{{/tags}} {{/tags}}

View File

@@ -38,6 +38,19 @@ class SwiftDispatcher {
const swift::PoundAvailableInfo*, const swift::PoundAvailableInfo*,
const swift::AvailabilitySpec*>; const swift::AvailabilitySpec*>;
template <typename E>
static constexpr bool IsFetchable = std::is_constructible_v<Handle, const E&>;
template <typename E>
static constexpr bool IsLocatable =
std::is_base_of_v<LocatableTag, TrapTagOf<E>> && !std::is_base_of_v<TypeTag, TrapTagOf<E>>;
template <typename E>
static constexpr bool IsDeclPointer = std::is_convertible_v<E, const swift::Decl*>;
template <typename E>
static constexpr bool IsTypePointer = std::is_convertible_v<E, const swift::TypeBase*>;
public: public:
// all references and pointers passed as parameters to this constructor are supposed to outlive // all references and pointers passed as parameters to this constructor are supposed to outlive
// the SwiftDispatcher // the SwiftDispatcher
@@ -63,7 +76,7 @@ class SwiftDispatcher {
using Label = std::remove_reference_t<decltype(label)>; using Label = std::remove_reference_t<decltype(label)>;
if (!label.valid()) { if (!label.valid()) {
const char* action; const char* action;
if constexpr (std::derived_from<UnspecifiedElementTag, typename Label::Tag>) { if constexpr (std::is_base_of_v<typename Label::Tag, UnspecifiedElementTag>) {
action = "replacing with unspecified element"; action = "replacing with unspecified element";
label = emitUnspecified(idOf(entry), field, index); label = emitUnspecified(idOf(entry), field, index);
} else { } else {
@@ -119,7 +132,7 @@ class SwiftDispatcher {
template <typename E> template <typename E>
std::optional<TrapLabel<ElementTag>> idOf(const E& entry) { std::optional<TrapLabel<ElementTag>> idOf(const E& entry) {
if constexpr (requires { entry.id; }) { if constexpr (HasId<E>::value) {
return entry.id; return entry.id;
} else { } else {
return std::nullopt; return std::nullopt;
@@ -129,14 +142,13 @@ class SwiftDispatcher {
// This method gives a TRAP label for already emitted AST node. // This method gives a TRAP label for already emitted AST node.
// If the AST node was not emitted yet, then the emission is dispatched to a corresponding // If the AST node was not emitted yet, then the emission is dispatched to a corresponding
// visitor (see `visit(T *)` methods below). // visitor (see `visit(T *)` methods below).
// clang-format off template <typename E, std::enable_if_t<IsFetchable<E>>* = nullptr>
template <typename E> TrapLabelOf<E> fetchLabel(const E& e, swift::Type type = {}) {
requires std::constructible_from<Handle, E*> if constexpr (std::is_constructible_v<bool, const E&>) {
TrapLabelOf<E> fetchLabel(const E* e, swift::Type type = {}) { if (!e) {
// clang-format on // this will be treated on emission
if (!e) { return undefined_label;
// this will be treated on emission }
return undefined_label;
} }
auto& stored = store[e]; auto& stored = store[e];
if (!stored.valid()) { if (!stored.valid()) {
@@ -162,11 +174,8 @@ class SwiftDispatcher {
return ret; return ret;
} }
// clang-format off template <typename E, std::enable_if_t<IsFetchable<E*>>* = nullptr>
template <typename E>
requires std::constructible_from<Handle, E*>
TrapLabelOf<E> fetchLabel(const E& e) { TrapLabelOf<E> fetchLabel(const E& e) {
// clang-format on
return fetchLabel(&e); return fetchLabel(&e);
} }
@@ -175,8 +184,7 @@ class SwiftDispatcher {
auto createEntry(const E& e) { auto createEntry(const E& e) {
auto found = store.find(&e); auto found = store.find(&e);
CODEQL_ASSERT(found != store.end(), "createEntry called on non-fetched label"); CODEQL_ASSERT(found != store.end(), "createEntry called on non-fetched label");
using Tag = ConcreteTrapTagOf<E>; auto label = TrapLabel<ConcreteTrapTagOf<E>>::unsafeCreateFromUntyped(found->second);
auto label = TrapLabel<Tag>::unsafeCreateFromUntyped(found->second);
if constexpr (IsLocatable<E>) { if constexpr (IsLocatable<E>) {
locationExtractor.attachLocation(sourceManager, e, label); locationExtractor.attachLocation(sourceManager, e, label);
} }
@@ -187,8 +195,7 @@ class SwiftDispatcher {
// an example is swift::Argument, that are created on the fly and thus have no stable pointer // an example is swift::Argument, that are created on the fly and thus have no stable pointer
template <typename E> template <typename E>
auto createUncachedEntry(const E& e) { auto createUncachedEntry(const E& e) {
using Tag = TrapTagOf<E>; auto label = trap.createTypedLabel<TrapTagOf<E>>();
auto label = trap.createTypedLabel<Tag>();
locationExtractor.attachLocation(sourceManager, &e, label); locationExtractor.attachLocation(sourceManager, &e, label);
return TrapClassOf<E>{label}; return TrapClassOf<E>{label};
} }
@@ -211,7 +218,7 @@ class SwiftDispatcher {
auto fetchRepeatedLabels(Iterable&& arg) { auto fetchRepeatedLabels(Iterable&& arg) {
using Label = decltype(fetchLabel(*arg.begin())); using Label = decltype(fetchLabel(*arg.begin()));
TrapLabelVectorWrapper<typename Label::Tag> ret; TrapLabelVectorWrapper<typename Label::Tag> ret;
if constexpr (requires { arg.size(); }) { if constexpr (HasSize<Iterable>::value) {
ret.data.reserve(arg.size()); ret.data.reserve(arg.size());
} }
for (auto&& e : arg) { for (auto&& e : arg) {
@@ -244,7 +251,7 @@ class SwiftDispatcher {
private: private:
template <typename E> template <typename E>
UntypedTrapLabel createLabel(const E& e, swift::Type type) { UntypedTrapLabel createLabel(const E& e, swift::Type type) {
if constexpr (requires { name(e); }) { if constexpr (IsDeclPointer<E> || IsTypePointer<E>) {
if (auto mangledName = name(e)) { if (auto mangledName = name(e)) {
if (shouldVisit(e)) { if (shouldVisit(e)) {
toBeVisited.emplace_back(e, type); toBeVisited.emplace_back(e, type);
@@ -259,7 +266,7 @@ class SwiftDispatcher {
template <typename E> template <typename E>
bool shouldVisit(const E& e) { bool shouldVisit(const E& e) {
if constexpr (std::convertible_to<E, const swift::Decl*>) { if constexpr (IsDeclPointer<E>) {
encounteredModules.insert(e->getModuleContext()); encounteredModules.insert(e->getModuleContext());
if (bodyEmissionStrategy.shouldEmitDeclBody(*e)) { if (bodyEmissionStrategy.shouldEmitDeclBody(*e)) {
extractedDeclaration(e); extractedDeclaration(e);
@@ -288,6 +295,18 @@ class SwiftDispatcher {
module->isNonSwiftModule(); module->isNonSwiftModule();
} }
template <typename T, typename = void>
struct HasSize : std::false_type {};
template <typename T>
struct HasSize<T, decltype(std::declval<T>().size(), void())> : std::true_type {};
template <typename T, typename = void>
struct HasId : std::false_type {};
template <typename T>
struct HasId<T, decltype(std::declval<T>().id, void())> : std::true_type {};
template <typename Tag, typename... Ts> template <typename Tag, typename... Ts>
TrapLabel<Tag> fetchLabelFromUnion(const llvm::PointerUnion<Ts...> u) { TrapLabel<Tag> fetchLabelFromUnion(const llvm::PointerUnion<Ts...> u) {
TrapLabel<Tag> ret{}; TrapLabel<Tag> ret{};
@@ -305,7 +324,7 @@ class SwiftDispatcher {
// on `BraceStmt`/`IfConfigDecl` elements), we cannot encounter a standalone `TypeRepr` there, // on `BraceStmt`/`IfConfigDecl` elements), we cannot encounter a standalone `TypeRepr` there,
// so we skip this case; extracting `TypeRepr`s here would be problematic as we would not be // so we skip this case; extracting `TypeRepr`s here would be problematic as we would not be
// able to provide the corresponding type // able to provide the corresponding type
if constexpr (!std::same_as<T, swift::TypeRepr*>) { if constexpr (!std::is_same_v<T, swift::TypeRepr*>) {
if (auto e = u.template dyn_cast<T>()) { if (auto e = u.template dyn_cast<T>()) {
output = fetchLabel(e); output = fetchLabel(e);
return true; return true;
@@ -329,8 +348,10 @@ class SwiftDispatcher {
virtual void visit(const swift::TypeBase* type) = 0; virtual void visit(const swift::TypeBase* type) = 0;
virtual void visit(const swift::CapturedValue* capture) = 0; virtual void visit(const swift::CapturedValue* capture) = 0;
template <typename T> template <typename T, std::enable_if<!std::is_base_of_v<swift::TypeRepr, T>>* = nullptr>
requires(!std::derived_from<T, swift::TypeRepr>) void visit(const T* e, swift::Type) { visit(e); } void visit(const T* e, swift::Type) {
visit(e);
}
const swift::SourceManager& sourceManager; const swift::SourceManager& sourceManager;
SwiftExtractorState& state; SwiftExtractorState& state;

View File

@@ -12,24 +12,19 @@
using namespace codeql; using namespace codeql;
swift::SourceRange detail::getSourceRange(const swift::Token& token) {
const auto charRange = token.getRange();
return {charRange.getStart(), charRange.getEnd()};
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager, void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::SourceRange& range, swift::SourceLoc start,
swift::SourceLoc end,
TrapLabel<LocatableTag> locatableLabel) { TrapLabel<LocatableTag> locatableLabel) {
if (!range) { if (!start.isValid() || !end.isValid()) {
// invalid locations seem to come from entities synthesized by the compiler // invalid locations seem to come from entities synthesized by the compiler
return; return;
} }
auto file = resolvePath(sourceManager.getDisplayNameForLoc(range.Start)); auto file = resolvePath(sourceManager.getDisplayNameForLoc(start));
DbLocation entry{{}}; DbLocation entry{{}};
entry.file = fetchFileLabel(file); entry.file = fetchFileLabel(file);
std::tie(entry.start_line, entry.start_column) = std::tie(entry.start_line, entry.start_column) = sourceManager.getLineAndColumnInBuffer(start);
sourceManager.getLineAndColumnInBuffer(range.Start); std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(end);
std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(range.End);
SwiftMangledName locName{"loc", entry.file, ':', entry.start_line, ':', entry.start_column, SwiftMangledName locName{"loc", entry.file, ':', entry.start_line, ':', entry.start_column,
':', entry.end_line, ':', entry.end_column}; ':', entry.end_line, ':', entry.end_column};
entry.id = trap.createTypedLabel<DbLocationTag>(locName); entry.id = trap.createTypedLabel<DbLocationTag>(locName);
@@ -48,6 +43,56 @@ TrapLabel<FileTag> SwiftLocationExtractor::emitFile(const std::filesystem::path&
return fetchFileLabel(resolvePath(file)); return fetchFileLabel(resolvePath(file));
} }
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::SourceRange& range,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, range.Start, range.End, locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::CapturedValue* capture,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, capture->getLoc(), locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::IfConfigClause* clause,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, clause->Loc, locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::AvailabilitySpec* spec,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, spec->getSourceRange(), locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::KeyPathExpr::Component* component,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, component->getSourceRange().Start,
component->getSourceRange().End, locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::Token* token,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, token->getRange().getStart(), token->getRange().getEnd(),
locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc loc,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, loc, loc, locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::DiagnosticInfo* diagInfo,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, diagInfo->Loc, locatableLabel);
}
TrapLabel<FileTag> SwiftLocationExtractor::fetchFileLabel(const std::filesystem::path& file) { TrapLabel<FileTag> SwiftLocationExtractor::fetchFileLabel(const std::filesystem::path& file) {
if (store.count(file)) { if (store.count(file)) {
return store[file]; return store[file];

View File

@@ -15,99 +15,104 @@ namespace codeql {
class TrapDomain; class TrapDomain;
namespace detail {
template <typename T>
concept HasSourceRange = requires(T e) {
e.getSourceRange();
};
template <typename T>
concept HasStartAndEndLoc = requires(T e) {
e.getStartLoc();
e.getEndLoc();
}
&&!(HasSourceRange<T>);
template <typename T>
concept HasOneLoc = requires(T e) {
e.getLoc();
}
&&!(HasSourceRange<T>)&&(!HasStartAndEndLoc<T>);
template <typename T>
concept HasOneLocField = requires(T e) {
e.Loc;
};
swift::SourceRange getSourceRange(const HasSourceRange auto& locatable) {
return locatable.getSourceRange();
}
swift::SourceRange getSourceRange(const HasStartAndEndLoc auto& locatable) {
if (locatable.getStartLoc() && locatable.getEndLoc()) {
return {locatable.getStartLoc(), locatable.getEndLoc()};
}
return {locatable.getStartLoc()};
}
swift::SourceRange getSourceRange(const HasOneLoc auto& locatable) {
return {locatable.getLoc()};
}
swift::SourceRange getSourceRange(const HasOneLocField auto& locatable) {
return {locatable.Loc};
}
swift::SourceRange getSourceRange(const swift::Token& token);
template <typename Locatable>
swift::SourceRange getSourceRange(const llvm::MutableArrayRef<Locatable>& locatables) {
if (locatables.empty()) {
return {};
}
auto startRange = getSourceRange(locatables.front());
auto endRange = getSourceRange(locatables.back());
if (startRange.Start && endRange.End) {
return {startRange.Start, endRange.End};
}
return {startRange.Start};
}
} // namespace detail
template <typename E>
concept IsLocatable = requires(E e) {
detail::getSourceRange(e);
};
class SwiftLocationExtractor { class SwiftLocationExtractor {
template <typename Locatable, typename = void>
struct HasSpecializedImplementation : std::false_type {};
public: public:
explicit SwiftLocationExtractor(TrapDomain& trap) : trap(trap) {} explicit SwiftLocationExtractor(TrapDomain& trap) : trap(trap) {}
TrapLabel<FileTag> emitFile(swift::SourceFile* file); TrapLabel<FileTag> emitFile(swift::SourceFile* file);
TrapLabel<FileTag> emitFile(const std::filesystem::path& file); TrapLabel<FileTag> emitFile(const std::filesystem::path& file);
// Emits a Location TRAP entry and attaches it to a `Locatable` trap label template <typename Locatable>
void attachLocation(const swift::SourceManager& sourceManager, void attachLocation(const swift::SourceManager& sourceManager,
const IsLocatable auto& locatable, const Locatable& locatable,
TrapLabel<LocatableTag> locatableLabel) { TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, detail::getSourceRange(locatable), locatableLabel); attachLocation(sourceManager, &locatable, locatableLabel);
} }
// Emits a Location TRAP entry and attaches it to a `Locatable` trap label
template <typename Locatable,
std::enable_if_t<!HasSpecializedImplementation<Locatable>::value>* = nullptr>
void attachLocation(const swift::SourceManager& sourceManager, void attachLocation(const swift::SourceManager& sourceManager,
const IsLocatable auto* locatable, const Locatable* locatable,
TrapLabel<LocatableTag> locatableLabel) { TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, *locatable, locatableLabel); attachLocationImpl(sourceManager, locatable->getStartLoc(), locatable->getEndLoc(),
locatableLabel);
}
template <typename Locatable,
std::enable_if_t<HasSpecializedImplementation<Locatable>::value>* = nullptr>
void attachLocation(const swift::SourceManager& sourceManager,
const Locatable* locatable,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, locatable, locatableLabel);
} }
private: private:
// Emits a Location TRAP entry for a list of swift entities and attaches it to a `Locatable` trap
// label
template <typename Locatable>
void attachLocationImpl(const swift::SourceManager& sourceManager,
const llvm::MutableArrayRef<Locatable>* locatables,
TrapLabel<LocatableTag> locatableLabel) {
if (locatables->empty()) {
return;
}
attachLocationImpl(sourceManager, locatables->front().getStartLoc(),
locatables->back().getEndLoc(), locatableLabel);
}
void attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc start,
swift::SourceLoc end,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc loc,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager, void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::SourceRange& range, const swift::SourceRange& range,
TrapLabel<LocatableTag> locatableLabel); TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::CapturedValue* capture,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::IfConfigClause* clause,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::AvailabilitySpec* spec,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::Token* token,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::DiagnosticInfo* token,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::KeyPathExpr::Component* component,
TrapLabel<LocatableTag> locatableLabel);
private: private:
TrapLabel<FileTag> fetchFileLabel(const std::filesystem::path& file); TrapLabel<FileTag> fetchFileLabel(const std::filesystem::path& file);
TrapDomain& trap; TrapDomain& trap;
std::unordered_map<std::filesystem::path, TrapLabel<FileTag>, codeql::PathHash> store; std::unordered_map<std::filesystem::path, TrapLabel<FileTag>, codeql::PathHash> store;
}; };
template <typename Locatable>
struct SwiftLocationExtractor::HasSpecializedImplementation<
Locatable,
decltype(std::declval<SwiftLocationExtractor>().attachLocationImpl(
std::declval<const swift::SourceManager&>(),
std::declval<const Locatable*>(),
std::declval<TrapLabel<LocatableTag>>()))> : std::true_type {};
} // namespace codeql } // namespace codeql

View File

@@ -13,9 +13,9 @@ using namespace codeql;
int main() { int main() {
std::map<const char*, std::vector<const char*>> unextracted; std::map<const char*, std::vector<const char*>> unextracted;
#define CHECK_CLASS(KIND, CLASS, PARENT) \ #define CHECK_CLASS(KIND, CLASS, PARENT) \
if constexpr (KIND##Translator::getPolicyFor##CLASS##KIND() == TranslatorPolicy::emitUnknown) { \ if (KIND##Translator::getPolicyFor##CLASS##KIND() == TranslatorPolicy::emitUnknown) { \
unextracted[#KIND].push_back(#CLASS #KIND); \ unextracted[#KIND].push_back(#CLASS #KIND); \
} }
#define DECL(CLASS, PARENT) CHECK_CLASS(Decl, CLASS, PARENT) #define DECL(CLASS, PARENT) CHECK_CLASS(Decl, CLASS, PARENT)

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <concepts>
#include <swift/AST/ASTVisitor.h> #include <swift/AST/ASTVisitor.h>
#include <swift/AST/TypeVisitor.h> #include <swift/AST/TypeVisitor.h>
@@ -20,6 +18,45 @@ class TranslatorBase {
: dispatcher{dispatcher}, logger{"translator/" + std::string(name)} {} : dispatcher{dispatcher}, logger{"translator/" + std::string(name)} {}
}; };
// define by macro metaprogramming member checkers
// see https://fekir.info/post/detect-member-variables/ for technical details
#define DEFINE_TRANSLATE_CHECKER(KIND, CLASS, PARENT) \
template <typename T, typename = void> \
struct HasTranslate##CLASS##KIND : std::false_type {}; \
\
template <typename T> \
struct HasTranslate##CLASS##KIND<T, decltype((void)std::declval<T>().translate##CLASS##KIND( \
std::declval<const swift::CLASS##KIND&>()), \
void())> : std::true_type {};
DEFINE_TRANSLATE_CHECKER(Decl, , )
#define DECL(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Decl, CLASS, PARENT)
#define ABSTRACT_DECL(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Decl, CLASS, PARENT)
#include "swift/AST/DeclNodes.def"
DEFINE_TRANSLATE_CHECKER(Stmt, , )
#define STMT(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Stmt, CLASS, PARENT)
#define ABSTRACT_STMT(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Stmt, CLASS, PARENT)
#include "swift/AST/StmtNodes.def"
DEFINE_TRANSLATE_CHECKER(Expr, , )
#define EXPR(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Expr, CLASS, PARENT)
#define ABSTRACT_EXPR(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Expr, CLASS, PARENT)
#include "swift/AST/ExprNodes.def"
DEFINE_TRANSLATE_CHECKER(Pattern, , )
#define PATTERN(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Pattern, CLASS, PARENT)
#include "swift/AST/PatternNodes.def"
DEFINE_TRANSLATE_CHECKER(Type, , )
#define TYPE(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Type, CLASS, PARENT)
#define ABSTRACT_TYPE(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(Type, CLASS, PARENT)
#include "swift/AST/TypeNodes.def"
DEFINE_TRANSLATE_CHECKER(TypeRepr, , )
#define TYPEREPR(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(TypeRepr, CLASS, PARENT)
#define ABSTRACT_TYPEREPR(CLASS, PARENT) DEFINE_TRANSLATE_CHECKER(TypeRepr, CLASS, PARENT)
#include "swift/AST/TypeReprNodes.def"
} // namespace detail } // namespace detail
enum class TranslatorPolicy { enum class TranslatorPolicy {
@@ -39,15 +76,11 @@ enum class TranslatorPolicy {
#define DEFINE_VISIT(KIND, CLASS, PARENT) \ #define DEFINE_VISIT(KIND, CLASS, PARENT) \
public: \ public: \
static constexpr TranslatorPolicy getPolicyFor##CLASS##KIND() { \ static constexpr TranslatorPolicy getPolicyFor##CLASS##KIND() { \
if constexpr (std::same_as<TrapTagOf<swift::CLASS##KIND>, void>) { \ if constexpr (std::is_same_v<TrapTagOf<swift::CLASS##KIND>, void>) { \
return TranslatorPolicy::ignore; \ return TranslatorPolicy::ignore; \
} else if constexpr (requires(CrtpSubclass x, swift::CLASS##KIND e) { \ } else if constexpr (detail::HasTranslate##CLASS##KIND<CrtpSubclass>::value) { \
x.translate##CLASS##KIND(e); \
}) { \
return TranslatorPolicy::translate; \ return TranslatorPolicy::translate; \
} else if constexpr (requires(CrtpSubclass x, swift::CLASS##KIND e) { \ } else if constexpr (detail::HasTranslate##PARENT<CrtpSubclass>::value) { \
x.translate##PARENT(e); \
}) { \
return TranslatorPolicy::translateParent; \ return TranslatorPolicy::translateParent; \
} else { \ } else { \
return TranslatorPolicy::emitUnknown; \ return TranslatorPolicy::emitUnknown; \
@@ -59,6 +92,7 @@ enum class TranslatorPolicy {
constexpr auto policy = getPolicyFor##CLASS##KIND(); \ constexpr auto policy = getPolicyFor##CLASS##KIND(); \
if constexpr (policy == TranslatorPolicy::ignore) { \ if constexpr (policy == TranslatorPolicy::ignore) { \
LOG_ERROR("Unexpected " #CLASS #KIND); \ LOG_ERROR("Unexpected " #CLASS #KIND); \
return; \
} else if constexpr (policy == TranslatorPolicy::translate) { \ } else if constexpr (policy == TranslatorPolicy::translate) { \
dispatcher.emit(static_cast<CrtpSubclass*>(this)->translate##CLASS##KIND(*e)); \ dispatcher.emit(static_cast<CrtpSubclass*>(this)->translate##CLASS##KIND(*e)); \
} else if constexpr (policy == TranslatorPolicy::translateParent) { \ } else if constexpr (policy == TranslatorPolicy::translateParent) { \

View File

@@ -9,7 +9,6 @@
#include <binlog/binlog.hpp> #include <binlog/binlog.hpp>
#include <cmath> #include <cmath>
#include <charconv> #include <charconv>
#include <concepts>
namespace codeql { namespace codeql {
@@ -83,8 +82,9 @@ class TrapLabel : public UntypedTrapLabel {
static TrapLabel unsafeCreateFromUntyped(UntypedTrapLabel label) { return TrapLabel{label.id_}; } static TrapLabel unsafeCreateFromUntyped(UntypedTrapLabel label) { return TrapLabel{label.id_}; }
template <typename SourceTag> template <typename SourceTag>
requires std::derived_from<SourceTag, Tag> TrapLabel(const TrapLabel<SourceTag>& other) TrapLabel(const TrapLabel<SourceTag>& other) : UntypedTrapLabel(other) {
: UntypedTrapLabel(other) {} static_assert(std::is_base_of_v<Tag, SourceTag>, "wrong label assignment!");
}
}; };
// wrapper class to allow directly assigning a vector of TrapLabel<A> to a vector of // wrapper class to allow directly assigning a vector of TrapLabel<A> to a vector of
@@ -96,8 +96,8 @@ struct TrapLabelVectorWrapper {
std::vector<TrapLabel<TagParam>> data; std::vector<TrapLabel<TagParam>> data;
template <typename DestinationTag> template <typename DestinationTag>
requires std::derived_from<Tag, DestinationTag>
operator std::vector<TrapLabel<DestinationTag>>() && { operator std::vector<TrapLabel<DestinationTag>>() && {
static_assert(std::is_base_of_v<DestinationTag, Tag>, "wrong label assignment!");
// reinterpret_cast is safe because TrapLabel instances differ only on the type, not the // reinterpret_cast is safe because TrapLabel instances differ only on the type, not the
// underlying data // underlying data
return std::move(reinterpret_cast<std::vector<TrapLabel<DestinationTag>>&>(data)); return std::move(reinterpret_cast<std::vector<TrapLabel<DestinationTag>>&>(data));