diff --git a/src/mlir/cxx/mlir/codegen_declarations.cc b/src/mlir/cxx/mlir/codegen_declarations.cc index faee4375..0b1492b4 100644 --- a/src/mlir/cxx/mlir/codegen_declarations.cc +++ b/src/mlir/cxx/mlir/codegen_declarations.cc @@ -23,6 +23,7 @@ // cxx #include #include +#include #include #include #include @@ -84,16 +85,7 @@ struct Codegen::TemplateParameterVisitor { }; auto Codegen::declaration(DeclarationAST* ast) -> DeclarationResult { - // if (ast) return visit(DeclarationVisitor{*this}, ast); - - // restrict for now to declarations that are not definitions - if (ast_cast(ast) || - ast_cast(ast) || - ast_cast(ast) || - ast_cast(ast)) { - return visit(DeclarationVisitor{*this}, ast); - } - + if (ast) return visit(DeclarationVisitor{*this}, ast); return {}; } @@ -149,6 +141,11 @@ auto Codegen::lambdaSpecifier(LambdaSpecifierAST* ast) auto Codegen::DeclarationVisitor::operator()(SimpleDeclarationAST* ast) -> DeclarationResult { + if (!gen.function_) { + // skip for now, as we only look for local variable declarations + return {}; + } + #if false for (auto node : ListView{ast->attributeList}) { auto value = gen.attributeSpecifier(node); @@ -223,32 +220,39 @@ auto Codegen::DeclarationVisitor::operator()(AsmDeclarationAST* ast) auto Codegen::DeclarationVisitor::operator()(NamespaceAliasDefinitionAST* ast) -> DeclarationResult { +#if false auto nestedNameSpecifierResult = gen.nestedNameSpecifier(ast->nestedNameSpecifier); auto unqualifiedIdResult = gen.unqualifiedId(ast->unqualifiedId); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(UsingDeclarationAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->usingDeclaratorList}) { auto value = gen.usingDeclarator(node); } +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(UsingEnumDeclarationAST* ast) -> DeclarationResult { +#if false auto enumTypeSpecifierResult = gen.specifier(ast->enumTypeSpecifier); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(UsingDirectiveAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->attributeList}) { auto value = gen.attributeSpecifier(node); } @@ -257,19 +261,23 @@ auto Codegen::DeclarationVisitor::operator()(UsingDirectiveAST* ast) gen.nestedNameSpecifier(ast->nestedNameSpecifier); auto unqualifiedIdResult = gen.unqualifiedId(ast->unqualifiedId); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(StaticAssertDeclarationAST* ast) -> DeclarationResult { +#if false auto expressionResult = gen.expression(ast->expression); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(AliasDeclarationAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->attributeList}) { auto value = gen.attributeSpecifier(node); } @@ -279,12 +287,14 @@ auto Codegen::DeclarationVisitor::operator()(AliasDeclarationAST* ast) } auto typeIdResult = gen.typeId(ast->typeId); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(OpaqueEnumDeclarationAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->attributeList}) { auto value = gen.attributeSpecifier(node); } @@ -297,6 +307,7 @@ auto Codegen::DeclarationVisitor::operator()(OpaqueEnumDeclarationAST* ast) for (auto node : ListView{ast->typeSpecifierList}) { auto value = gen.specifier(node); } +#endif return {}; } @@ -333,15 +344,8 @@ auto Codegen::DeclarationVisitor::operator()(FunctionDefinitionAST* ast) if (ast->symbol->hasCLinkage()) { name = to_string(ast->symbol->name()); } else { - // todo: external name mangling - - std::ranges::for_each(path | std::views::reverse, [&](auto& part) { - name += "::"; - name += part; - }); - - // generate unique names until we have proper name mangling - name += std::format("_{}", ++gen.count_); + ExternalNameEncoder encoder; + name = encoder.encode(ast->symbol); } auto guard = mlir::OpBuilder::InsertionGuard(gen.builder_); @@ -379,14 +383,7 @@ auto Codegen::DeclarationVisitor::operator()(FunctionDefinitionAST* ast) const auto endLoc = gen.getLocation(ast->lastSourceLocation()); if (!gen.builder_.getBlock()->mightHaveTerminator()) { - llvm::SmallVector exitBlockArgs; - - if (gen.exitValue_) { - exitBlockArgs.push_back(gen.exitValue_.getResult()); - } - - gen.builder_.create(endLoc, exitBlockArgs, - gen.exitBlock_); + gen.builder_.create(endLoc, gen.exitBlock_); } gen.builder_.setInsertionPointToEnd(gen.exitBlock_); @@ -415,6 +412,7 @@ auto Codegen::DeclarationVisitor::operator()(FunctionDefinitionAST* ast) auto Codegen::DeclarationVisitor::operator()(TemplateDeclarationAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->templateParameterList}) { auto value = gen.templateParameter(node); } @@ -422,26 +420,30 @@ auto Codegen::DeclarationVisitor::operator()(TemplateDeclarationAST* ast) auto requiresClauseResult = gen.requiresClause(ast->requiresClause); auto declarationResult = gen.declaration(ast->declaration); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(ConceptDefinitionAST* ast) -> DeclarationResult { +#if false auto expressionResult = gen.expression(ast->expression); +#endif return {}; } auto Codegen::DeclarationVisitor::operator()(DeductionGuideAST* ast) -> DeclarationResult { +#if false auto explicitSpecifierResult = gen.specifier(ast->explicitSpecifier); auto parameterDeclarationClauseResult = gen.parameterDeclarationClause(ast->parameterDeclarationClause); auto templateIdResult = gen.unqualifiedId(ast->templateId); - +#endif return {}; } @@ -525,6 +527,7 @@ auto Codegen::DeclarationVisitor::operator()(ModuleImportDeclarationAST* ast) auto Codegen::DeclarationVisitor::operator()(ParameterDeclarationAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->attributeList}) { auto value = gen.attributeSpecifier(node); } @@ -535,7 +538,7 @@ auto Codegen::DeclarationVisitor::operator()(ParameterDeclarationAST* ast) auto declaratorResult = gen.declarator(ast->declarator); auto expressionResult = gen.expression(ast->expression); - +#endif return {}; } diff --git a/src/parser/cxx/external_name_encoder.cc b/src/parser/cxx/external_name_encoder.cc index a60994e7..4b3e0966 100644 --- a/src/parser/cxx/external_name_encoder.cc +++ b/src/parser/cxx/external_name_encoder.cc @@ -27,188 +27,669 @@ namespace cxx { -struct ExternalNameEncoder::NameVisitor { - ExternalNameEncoder& encoder; +namespace { - void operator()(const Identifier* name) {} +[[nodiscard]] auto is_global_namespace(Symbol* symbol) -> bool { + if (!symbol) return false; + if (!symbol->isNamespace()) return false; + if (symbol->enclosingSymbol()) return false; + return true; +} - void operator()(const OperatorId* name) {} +[[nodiscard]] auto enclosing_class_or_namespace(Symbol* symbol) -> Symbol* { + if (!symbol) return nullptr; + auto parent = symbol->enclosingSymbol(); + if (!parent) return nullptr; + if (!parent->isClassOrNamespace()) return nullptr; + return parent; +} - void operator()(const DestructorId* name) {} +[[nodiscard]] auto is_std_namespace(Symbol* symbol) -> bool { + auto parent = enclosing_class_or_namespace(symbol); + if (!parent) return false; - void operator()(const LiteralOperatorId* name) {} + if (!is_global_namespace(parent)) return false; - void operator()(const ConversionFunctionId* name) {} + auto id = name_cast(symbol->name()); + if (!id) return false; - void operator()(const TemplateId* name) {} -}; + if (id->name() != "std") return false; + + return true; +} + +} // namespace -struct ExternalNameEncoder::TypeVisitor { +struct ExternalNameEncoder::EncodeType { ExternalNameEncoder& encoder; - void operator()(const VoidType* type) { encoder.out("v"); } + auto operator()(const VoidType* type) -> bool { + encoder.out("v"); + return false; + } + + auto operator()(const NullptrType* type) -> bool { + encoder.out("Dn"); + return false; + } + + auto operator()(const DecltypeAutoType* type) -> bool { + encoder.out("Dc"); + return false; + } + + auto operator()(const AutoType* type) -> bool { + encoder.out("Da"); + return false; + } + + auto operator()(const BoolType* type) -> bool { + encoder.out("b"); + return false; + } + + auto operator()(const SignedCharType* type) -> bool { + encoder.out("a"); + return false; + } - void operator()(const NullptrType* type) { encoder.out("Dn"); } + auto operator()(const ShortIntType* type) -> bool { + encoder.out("s"); + return false; + } + + auto operator()(const IntType* type) -> bool { + encoder.out("i"); + return false; + } - void operator()(const DecltypeAutoType* type) { encoder.out("Dc"); } + auto operator()(const LongIntType* type) -> bool { + encoder.out("l"); + return false; + } - void operator()(const AutoType* type) { encoder.out("Da"); } + auto operator()(const LongLongIntType* type) -> bool { + encoder.out("x"); + return false; + } - void operator()(const BoolType* type) { encoder.out("b"); } + auto operator()(const Int128Type* type) -> bool { + encoder.out("n"); + return false; + } - void operator()(const SignedCharType* type) { encoder.out("a"); } + auto operator()(const UnsignedCharType* type) -> bool { + encoder.out("h"); + return false; + } - void operator()(const ShortIntType* type) { encoder.out("s"); } + auto operator()(const UnsignedShortIntType* type) -> bool { + encoder.out("t"); + return false; + } - void operator()(const IntType* type) { encoder.out("i"); } + auto operator()(const UnsignedIntType* type) -> bool { + encoder.out("j"); + return false; + } - void operator()(const LongIntType* type) { encoder.out("l"); } + auto operator()(const UnsignedLongIntType* type) -> bool { + encoder.out("m"); + return false; + } - void operator()(const LongLongIntType* type) { encoder.out("x"); } + auto operator()(const UnsignedLongLongIntType* type) -> bool { + encoder.out("y"); + return false; + } - void operator()(const Int128Type* type) { encoder.out("n"); } + auto operator()(const UnsignedInt128Type* type) -> bool { + encoder.out("o"); + return false; + } - void operator()(const UnsignedCharType* type) { encoder.out("h"); } + auto operator()(const CharType* type) -> bool { + encoder.out("c"); + return false; + } - void operator()(const UnsignedShortIntType* type) { encoder.out("t"); } + auto operator()(const Char8Type* type) -> bool { + encoder.out("Du"); + return false; + } - void operator()(const UnsignedIntType* type) { encoder.out("j"); } + auto operator()(const Char16Type* type) -> bool { + encoder.out("Ds"); + return false; + } - void operator()(const UnsignedLongIntType* type) { encoder.out("m"); } + auto operator()(const Char32Type* type) -> bool { + encoder.out("Di"); + return false; + } - void operator()(const UnsignedLongLongIntType* type) { encoder.out("y"); } + auto operator()(const WideCharType* type) -> bool { + encoder.out("w"); + return false; + } - void operator()(const UnsignedInt128Type* type) { encoder.out("o"); } + auto operator()(const FloatType* type) -> bool { + encoder.out("f"); + return false; + } - void operator()(const CharType* type) { encoder.out("c"); } + auto operator()(const DoubleType* type) -> bool { + encoder.out("d"); + return false; + } - void operator()(const Char8Type* type) { encoder.out("Du"); } + auto operator()(const LongDoubleType* type) -> bool { + encoder.out("e"); + return false; + } - void operator()(const Char16Type* type) { encoder.out("Ds"); } + auto operator()(const QualType* type) -> bool { + if (type->isVolatile()) encoder.out("V"); + if (type->isConst()) encoder.out("K"); + encoder.encodeType(type->elementType()); + return true; + } - void operator()(const Char32Type* type) { encoder.out("Di"); } + auto operator()(const BoundedArrayType* type) -> bool { + encoder.out(std::format("A{}_", type->size())); + encoder.encodeType(type->elementType()); + return true; + } - void operator()(const WideCharType* type) { encoder.out("w"); } + auto operator()(const UnboundedArrayType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const FloatType* type) { encoder.out("f"); } + auto operator()(const PointerType* type) -> bool { + encoder.out("P"); + encoder.encodeType(type->elementType()); + return true; + } - void operator()(const DoubleType* type) { encoder.out("d"); } + auto operator()(const LvalueReferenceType* type) -> bool { + encoder.out("R"); + encoder.encodeType(type->elementType()); + return true; + } - void operator()(const LongDoubleType* type) { encoder.out("e"); } + auto operator()(const RvalueReferenceType* type) -> bool { + encoder.out("O"); + encoder.encodeType(type->elementType()); + return true; + } - void operator()(const QualType* type) {} + auto operator()(const FunctionType* type) -> bool { + if (is_volatile(type->cvQualifiers())) encoder.out("V"); + if (is_const(type->cvQualifiers())) encoder.out("K"); - void operator()(const BoundedArrayType* type) {} + if (type->isNoexcept()) { + // todo: computed noexcept + encoder.out("N"); + } - void operator()(const UnboundedArrayType* type) {} + // todo: "Y" prefix for the bare function type encodes extern "C" + encoder.out("F"); - void operator()(const PointerType* type) {} + encoder.encodeBareFunctionType(type); - void operator()(const LvalueReferenceType* type) {} + if (type->refQualifier() == RefQualifier::kLvalue) + encoder.out("R"); + else if (type->refQualifier() == RefQualifier::kRvalue) + encoder.out("O"); - void operator()(const RvalueReferenceType* type) {} + encoder.out("E"); + return true; + } - void operator()(const FunctionType* type) {} + auto operator()(const ClassType* type) -> bool { + if (!type->symbol()->name()) { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const ClassType* type) {} + encoder.encodeName(type->symbol()); + return true; + } - void operator()(const EnumType* type) {} + auto operator()(const EnumType* type) -> bool { + if (!type->symbol()->name()) { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } + encoder.encodeName(type->symbol()); + return true; + } - void operator()(const ScopedEnumType* type) {} + auto operator()(const ScopedEnumType* type) -> bool { + if (!type->symbol()->name()) { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } + encoder.encodeName(type->symbol()); + return true; + } - void operator()(const MemberObjectPointerType* type) {} + auto operator()(const MemberObjectPointerType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const MemberFunctionPointerType* type) {} + auto operator()(const MemberFunctionPointerType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const NamespaceType* type) {} + auto operator()(const NamespaceType* type) -> bool { return false; } - void operator()(const TypeParameterType* type) {} + auto operator()(const TypeParameterType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const TemplateTypeParameterType* type) {} + auto operator()(const TemplateTypeParameterType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const UnresolvedNameType* type) {} + auto operator()(const UnresolvedNameType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const UnresolvedBoundedArrayType* type) {} + auto operator()(const UnresolvedBoundedArrayType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const UnresolvedUnderlyingType* type) {} + auto operator()(const UnresolvedUnderlyingType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const OverloadSetType* type) {} + auto operator()(const OverloadSetType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } - void operator()(const BuiltinVaListType* type) {} + auto operator()(const BuiltinVaListType* type) -> bool { + cxx_runtime_error(std::format("todo encode type '{}'", to_string(type))); + return false; + } }; -struct ExternalNameEncoder::SymbolVisitor { +struct ExternalNameEncoder::EncodeUnqualifiedName { ExternalNameEncoder& encoder; + Symbol* symbol = nullptr; - void operator()(NamespaceSymbol* symbol) {} + void operator()(const Identifier* id) { + if (auto function = symbol_cast(symbol)) { + if (function->isConstructor()) { + out("C2"); + return; + } + } - void operator()(ConceptSymbol* symbol) {} + out(std::format("{}{}", id->name().length(), id->name())); + } - void operator()(ClassSymbol* symbol) {} + void operator()(const OperatorId* name) { + auto is_unary = [&] { + auto function = symbol_cast(symbol); + if (!function) { + cxx_runtime_error( + std::format("cannot encode operator '{}' for non-function symbol", + to_string(name))); + } + + auto functionType = type_cast(function->type()); + if (!functionType) { + cxx_runtime_error( + std::format("cannot encode operator '{}' for non-function type", + to_string(name))); + } + + bool unary = false; + switch (name->op()) { + case TokenKind::T_PLUS: + case TokenKind::T_MINUS: + case TokenKind::T_AMP: + case TokenKind::T_STAR: { + auto argc = functionType->parameterTypes().size(); + if (argc == 0) + unary = true; + else if (argc == 1 && !function->enclosingSymbol()->isClass()) + unary = true; + break; + } + + default: + break; + } // switch + + return unary; + }; + + const auto unary = is_unary(); + + switch (name->op()) { + case TokenKind::T_NEW: + out("nw"); + break; + case TokenKind::T_NEW_ARRAY: + out("na"); + break; + case TokenKind::T_DELETE: + out("dl"); + break; + case TokenKind::T_DELETE_ARRAY: + out("da"); + break; + case TokenKind::T_CO_AWAIT: + out("aw"); + break; + case TokenKind::T_PLUS: + out(unary ? "ps" : "pl"); + break; + case TokenKind::T_MINUS: + out(unary ? "ng" : "mi"); + break; + case TokenKind::T_AMP: + out(unary ? "ad" : "an"); + break; + case TokenKind::T_STAR: + out(unary ? "de" : "ml"); + break; + case TokenKind::T_TILDE: + out("co"); + break; + case TokenKind::T_SLASH: + out("dv"); + break; + case TokenKind::T_PERCENT: + out("rm"); + break; + case TokenKind::T_BAR: + out("or"); + break; + case TokenKind::T_CARET: + out("eo"); + break; + case TokenKind::T_EQUAL: + out("aS"); + break; + case TokenKind::T_PLUS_EQUAL: + out("pL"); + break; + case TokenKind::T_MINUS_EQUAL: + out("mI"); + break; + case TokenKind::T_STAR_EQUAL: + out("mL"); + break; + case TokenKind::T_SLASH_EQUAL: + out("dV"); + break; + case TokenKind::T_PERCENT_EQUAL: + out("rM"); + break; + case TokenKind::T_AMP_EQUAL: + out("aN"); + break; + case TokenKind::T_BAR_EQUAL: + out("oR"); + break; + case TokenKind::T_CARET_EQUAL: + out("eO"); + break; + case TokenKind::T_LESS_LESS: + out("ls"); + break; + case TokenKind::T_GREATER_GREATER: + out("rs"); + break; + case TokenKind::T_LESS_LESS_EQUAL: + out("lS"); + break; + case TokenKind::T_GREATER_GREATER_EQUAL: + out("rS"); + break; + case TokenKind::T_EQUAL_EQUAL: + out("eq"); + break; + case TokenKind::T_EXCLAIM_EQUAL: + out("ne"); + break; + case TokenKind::T_LESS: + out("lt"); + break; + case TokenKind::T_GREATER: + out("gt"); + break; + case TokenKind::T_LESS_EQUAL: + out("le"); + break; + case TokenKind::T_GREATER_EQUAL: + out("ge"); + break; + case TokenKind::T_LESS_EQUAL_GREATER: + out("ss"); + break; + case TokenKind::T_EXCLAIM: + out("nt"); + break; + case TokenKind::T_AMP_AMP: + out("aa"); + break; + case TokenKind::T_BAR_BAR: + out("oo"); + break; + case TokenKind::T_PLUS_PLUS: + out("pp"); + break; + case TokenKind::T_MINUS_MINUS: + out("mm"); + break; + case TokenKind::T_COMMA: + out("cm"); + break; + case TokenKind::T_MINUS_GREATER_STAR: + out("pm"); + break; + case TokenKind::T_MINUS_GREATER: + out("pt"); + break; + case TokenKind::T_LPAREN: + out("cl"); + break; + case TokenKind::T_LBRACKET: + out("ix"); + break; + case TokenKind::T_QUESTION: + out("qu"); + break; + default: + cxx_runtime_error( + std::format("cannot encode operator '{}'", to_string(name))); + } // switch + } - void operator()(EnumSymbol* symbol) {} + void operator()(const DestructorId* name) { out("D2"); } - void operator()(ScopedEnumSymbol* symbol) {} + void operator()(const LiteralOperatorId* name) { + out("ll"); + encoder.out(std::format("{}{}", name->name().length(), name->name())); + } - void operator()(FunctionSymbol* symbol) {} + void operator()(const ConversionFunctionId* name) { + out("cv"); + encoder.encodeType(name->type()); + } - void operator()(TypeAliasSymbol* symbol) {} + void operator()(const TemplateId* name) { + cxx_runtime_error("template names not supported yet"); + } - void operator()(VariableSymbol* symbol) {} + void out(std::string_view str) { encoder.out(str); } +}; - void operator()(FieldSymbol* symbol) {} +ExternalNameEncoder::ExternalNameEncoder() {} - void operator()(ParameterSymbol* symbol) {} +auto ExternalNameEncoder::encode(Symbol* symbol) -> std::string { + if (auto functionSymbol = symbol_cast(symbol)) { + return encodeFunction(functionSymbol); + } - void operator()(ParameterPackSymbol* symbol) {} + return encodeData(symbol); +} - void operator()(EnumeratorSymbol* symbol) {} +auto ExternalNameEncoder::encode(const Type* type) -> std::string { + std::string externalName; + std::swap(externalName, out_); - void operator()(FunctionParametersSymbol* symbol) {} + encodeType(type); - void operator()(TemplateParametersSymbol* symbol) {} + std::swap(externalName, out_); + return externalName; +} - void operator()(BlockSymbol* symbol) {} +auto ExternalNameEncoder::encodeData(Symbol* symbol) -> std::string { + std::string externalName; + std::swap(externalName, out_); + if (is_global_namespace(enclosing_class_or_namespace(symbol))) { + auto id = name_cast(symbol->name()); + out(id->name()); + } else { + out("_Z"); + encodeName(symbol); + } + std::swap(externalName, out_); + return externalName; +} - void operator()(LambdaSymbol* symbol) {} +auto ExternalNameEncoder::encodeFunction(FunctionSymbol* function) + -> std::string { + std::string externalName; + std::swap(externalName, out_); + + const auto id = name_cast(function->name()); + + if (id && (function->hasCLinkage() || + (id->name() == "main" && + is_global_namespace(function->enclosingSymbol())))) { + out(id->name()); + } else { + out("_Z"); + encodeName(function); + auto functionType = type_cast(function->type()); + encodeBareFunctionType(functionType); + } - void operator()(TypeParameterSymbol* symbol) {} + std::swap(externalName, out_); - void operator()(NonTypeParameterSymbol* symbol) {} + return externalName; +} - void operator()(TemplateTypeParameterSymbol* symbol) {} +void ExternalNameEncoder::encodeName(Symbol* symbol) { + if (encodeNestedName(symbol)) return; + if (encodeUnscopedName(symbol)) return; - void operator()(ConstraintTypeParameterSymbol* symbol) {} + cxx_runtime_error(std::format("cannot encode name for symbol '{}'", + to_string(symbol->type(), symbol->name()))); +} - void operator()(OverloadSetSymbol* symbol) {} +auto ExternalNameEncoder::encodeNestedName(Symbol* symbol) -> bool { + auto parent = enclosing_class_or_namespace(symbol); + if (!parent) return false; + if (is_global_namespace(parent)) return false; + if (is_std_namespace(parent)) return false; + + out("N"); + // todo: encode cv qualifiers + // todo: encode ref qualifier + encodePrefix(parent); + encodeUnqualifiedName(symbol); + out("E"); + return true; +} - void operator()(BaseClassSymbol* symbol) {} +auto ExternalNameEncoder::encodeUnscopedName(Symbol* symbol) -> bool { + if (is_std_namespace(enclosing_class_or_namespace(symbol))) { + out("St"); + } - void operator()(UsingDeclarationSymbol* symbol) {} -}; + encodeUnqualifiedName(symbol); + return true; +} -ExternalNameEncoder::ExternalNameEncoder() {} +void ExternalNameEncoder::encodePrefix(Symbol* symbol) { + if (encodeSubstitution(symbol->type())) return; -void ExternalNameEncoder::out(std::string_view s) { externalName_.append(s); } + if (auto parent = enclosing_class_or_namespace(symbol); + parent && !is_global_namespace(parent)) { + encodePrefix(parent); + } -auto ExternalNameEncoder::encode(Symbol* symbol) -> std::string { - std::string externalName; - if (symbol) { - std::swap(externalName, externalName_); - visit(SymbolVisitor{*this}, symbol); - std::swap(externalName, externalName_); + enterSubstitution(symbol->type()); + encodeUnqualifiedName(symbol); +} + +void ExternalNameEncoder::encodeTemplatePrefix(Symbol* symbol) {} + +void ExternalNameEncoder::encodeUnqualifiedName(Symbol* symbol) { + visit(EncodeUnqualifiedName{*this, symbol}, symbol->name()); +} + +void ExternalNameEncoder::encodeBareFunctionType( + const FunctionType* functionType, bool includeReturnType) { + if (includeReturnType) { + encodeType(functionType->returnType()); + } + + for (auto param : functionType->parameterTypes()) { + encodeType(param); + } + + if (functionType->parameterTypes().empty()) { + out("v"); + } + + if (functionType->isVariadic()) { + out("z"); } - return externalName; } -auto ExternalNameEncoder::encode(const Type* type) -> std::string { - std::string externalName; - if (type) { - std::swap(externalName, externalName_); - visit(TypeVisitor{*this}, type); - std::swap(externalName, externalName_); +void ExternalNameEncoder::encodeType(const Type* type) { + if (encodeSubstitution(type)) return; + if (!visit(EncodeType{*this}, type)) return; + enterSubstitution(type); +} + +auto ExternalNameEncoder::encodeSubstitution(const Type* type) -> bool { + auto it = substs_.find(type); + if (it == substs_.end()) return false; + + const auto index = it->second; + + if (index == 0) { + out("S_"); + return true; } - return externalName; + + out(std::format("S{}_", index - 1)); + return true; +} + +void ExternalNameEncoder::enterSubstitution(const Type* type) { + const auto index = substCount_; + ++substCount_; + + substs_.emplace(type, index); } } // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/external_name_encoder.h b/src/parser/cxx/external_name_encoder.h index 96724d85..2b7d11fe 100644 --- a/src/parser/cxx/external_name_encoder.h +++ b/src/parser/cxx/external_name_encoder.h @@ -24,7 +24,8 @@ #include #include -#include +#include +#include namespace cxx { @@ -36,14 +37,35 @@ class ExternalNameEncoder { [[nodiscard]] auto encode(const Type* type) -> std::string; private: - void out(std::string_view s); + [[nodiscard]] auto encodeFunction(FunctionSymbol* function) -> std::string; + [[nodiscard]] auto encodeData(Symbol* symbol) -> std::string; - struct NameVisitor; - struct TypeVisitor; - struct SymbolVisitor; + void encodePrefix(Symbol* symbol); + void encodeTemplatePrefix(Symbol* symbol); + void encodeUnqualifiedName(Symbol* symbol); + + void encodeName(Symbol* symbol); + [[nodiscard]] auto encodeNestedName(Symbol* symbol) -> bool; + [[nodiscard]] auto encodeUnscopedName(Symbol* symbol) -> bool; + [[nodiscard]] auto encodeOperatorName(const Name* name, bool isUnary) + -> std::string_view; + + void encodeType(const Type* type); + void encodeBareFunctionType(const FunctionType* functionType, + bool includeReturnType = false); + + [[nodiscard]] auto encodeSubstitution(const Type* type) -> bool; + void enterSubstitution(const Type* type); + + void out(std::string_view str) { out_.append(str); } + + struct EncodeType; + struct EncodeUnqualifiedName; private: - std::string externalName_; + std::unordered_map substs_; + std::string out_; + int substCount_ = 0; }; } // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index df0e7cbf..ffaf6a0b 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -7174,6 +7174,7 @@ auto Parser::parse_linkage_specification(DeclarationAST*& yyast) -> bool { SourceLocation externLoc; List* attributes = nullptr; SourceLocation stringLiteralLoc; + bool isExternC = false; auto lookat_linkage_specification = [&] { LookaheadParser lookahead{this}; @@ -7186,9 +7187,31 @@ auto Parser::parse_linkage_specification(DeclarationAST*& yyast) -> bool { lookahead.commit(); + isExternC = unit->literal(stringLiteralLoc)->value() == "\"C\""; + return true; }; + auto update_linkage = [&](DeclarationAST* declaration) { + if (!declaration) return; + if (!isExternC) return; + + if (auto simpleDecl = ast_cast(declaration)) { + for (auto declarator : ListView{simpleDecl->initDeclaratorList}) { + auto func = symbol_cast(declarator->symbol); + if (!func) continue; + func->setHasCxxLinkage(false); + } + return; + } + + if (auto functionDecl = ast_cast(declaration)) { + if (auto func = symbol_cast(functionDecl->symbol)) { + func->setHasCxxLinkage(false); + } + } + }; + if (!lookat_linkage_specification()) return false; SourceLocation lbraceLoc; @@ -7210,6 +7233,10 @@ auto Parser::parse_linkage_specification(DeclarationAST*& yyast) -> bool { expect(TokenKind::T_RBRACE, ast->rbraceLoc); } + for (auto declaration : ListView{ast->declarationList}) { + update_linkage(declaration); + } + return true; } @@ -7217,6 +7244,8 @@ auto Parser::parse_linkage_specification(DeclarationAST*& yyast) -> bool { if (!parse_declaration(declaration, BindingContext::kNamespace)) return false; + update_linkage(declaration); + auto ast = make_node(pool_); yyast = ast;