diff --git a/src/frontend/cxx/frontend.cc b/src/frontend/cxx/frontend.cc index e51e8ed2..89e6a894 100644 --- a/src/frontend/cxx/frontend.cc +++ b/src/frontend/cxx/frontend.cc @@ -369,7 +369,9 @@ auto runOnFile(const CLI& cli, const std::string& fileName) -> bool { auto ir = codegen(unit.ast()); mlir::OpPrintingFlags flags; - flags.enableDebugInfo(true, true); + if (cli.opt_g) { + flags.enableDebugInfo(true, true); + } ir.module->print(llvm::outs(), flags); } #endif diff --git a/src/mlir/cxx/mlir/CxxOps.td b/src/mlir/cxx/mlir/CxxOps.td index f2dab4be..1e5ffbcc 100644 --- a/src/mlir/cxx/mlir/CxxOps.td +++ b/src/mlir/cxx/mlir/CxxOps.td @@ -20,34 +20,85 @@ include "mlir/IR/OpBase.td" include "mlir/IR/AttrTypeBase.td" +include "mlir/IR/SymbolInterfaces.td" +include "mlir/Interfaces/FunctionInterfaces.td" +include "mlir/Interfaces/SideEffectInterfaces.td" def Cxx_Dialect : Dialect { let name = "cxx"; let cppNamespace = "mlir::cxx"; let useDefaultTypePrinterParser = 1; - let dependentDialects = [ - "mlir::func::FuncDialect", - "mlir::cf::ControlFlowDialect", - "mlir::scf::SCFDialect", + let dependentDialects = ["mlir::func::FuncDialect", + "mlir::cf::ControlFlowDialect", + "mlir::scf::SCFDialect", ]; } -class Cxx_Type traits = []> : TypeDef { - let mnemonic = typeMnemonic; +class Cxx_Type traits = []> + : TypeDef { + let mnemonic = typeMnemonic; } -class Cxx_Op traits = []> : Op { -} +class Cxx_Op traits = []> + : Op {} def Cxx_ExprType : Cxx_Type<"Expr", "expr">; +def Cxx_FuncOp : Cxx_Op<"func", [FunctionOpInterface, IsolatedFromAbove]> { + let arguments = (ins SymbolNameAttr:$sym_name, + TypeAttrOf:$function_type, + OptionalAttr:$arg_attrs, + OptionalAttr:$res_attrs); + + let regions = (region AnyRegion:$body); + + let builders = [OpBuilder<(ins "StringRef":$name, "FunctionType":$type, + CArg<"ArrayRef", "{}">:$attrs)>]; + + let extraClassDeclaration = + [{ + auto getArgumentTypes() -> ArrayRef { return getFunctionType().getInputs(); } + auto getResultTypes() -> ArrayRef { return getFunctionType().getResults(); } + auto getCallableRegion() -> Region* { return &getBody(); } + }]; + + let hasCustomAssemblyFormat = 1; + let skipDefaultBuilders = 1; +} + +def Cxx_ReturnOp : Cxx_Op<"return", [Pure, HasParent<"FuncOp">, Terminator]> { + let arguments = (ins Variadic:$input); + + let builders = [OpBuilder<(ins), [{ build($_builder, $_state, {}); }]>]; + + let extraClassDeclaration = [{ + bool hasOperand() { return getNumOperands() != 0; } + }]; + + let hasVerifier = 0; +} + +def Cxx_CallOp : Cxx_Op<"call"> { + let arguments = (ins Cxx_ExprType:$callee, Variadic:$arguments); + let results = (outs Cxx_ExprType:$result); + let assemblyFormat = + "$callee `(` $arguments `:` type($arguments) `)` attr-dict `:` " + "type($result)"; + let builders = + [OpBuilder< + (ins "mlir::Value":$callee, "mlir::ValueRange":$arguments), + [{ build($_builder, $_state, $_builder.getType(), callee, arguments); }]>, + ]; +} + def TodoExprOp : Cxx_Op<"todo.expr"> { let arguments = (ins StrAttr:$message); let results = (outs Cxx_ExprType:$result); let assemblyFormat = "$message attr-dict `:` type($result)"; - let builders = [ - OpBuilder<(ins "::llvm::StringRef":$message), - [{ build($_builder, $_state, $_builder.getType(), message); }]>, + let builders = + [OpBuilder< + (ins "::llvm::StringRef":$message), + [{ build($_builder, $_state, $_builder.getType(), message); }]>, ]; } @@ -67,9 +118,10 @@ def ImplicitCastOp : Cxx_Op<"implicit.cast"> { let arguments = (ins StrAttr:$cast, Cxx_ExprType:$value); let results = (outs Cxx_ExprType:$result); let assemblyFormat = "$cast `(` $value `)` attr-dict `:` type($result)"; - let builders = [ - OpBuilder<(ins "llvm::StringRef":$cast, "mlir::Value":$value), - [{ build($_builder, $_state, $_builder.getType(), cast, value); }]>, + let builders = + [OpBuilder< + (ins "llvm::StringRef":$cast, "mlir::Value":$value), + [{ build($_builder, $_state, $_builder.getType(), cast, value); }]>, ]; } @@ -77,9 +129,10 @@ def IntLiteralOp : Cxx_Op<"int.literal"> { let arguments = (ins I64Attr:$value); let results = (outs Cxx_ExprType:$result); let assemblyFormat = "$value attr-dict `:` type($result)"; - let builders = [ - OpBuilder<(ins "int64_t":$value), - [{ build($_builder, $_state, $_builder.getType(), value); }]>, + let builders = + [OpBuilder< + (ins "int64_t":$value), + [{ build($_builder, $_state, $_builder.getType(), value); }]>, ]; } @@ -87,33 +140,21 @@ def IdOp : Cxx_Op<"id"> { let arguments = (ins StrAttr:$name); let results = (outs Cxx_ExprType:$result); let assemblyFormat = "$name attr-dict `:` type($result)"; - let builders = [ - OpBuilder<(ins "llvm::StringRef":$name), - [{ build($_builder, $_state, $_builder.getType(), name); }]>, + let builders = + [OpBuilder< + (ins "llvm::StringRef":$name), + [{ build($_builder, $_state, $_builder.getType(), name); }]>, ]; } def BinOp : Cxx_Op<"binary"> { let arguments = (ins StrAttr:$op, Cxx_ExprType:$lhs, Cxx_ExprType:$rhs); let results = (outs Cxx_ExprType:$result); - let assemblyFormat = "`op` $op `(` $lhs `,` $rhs `)` attr-dict `:` type($result)"; - let builders = [ - OpBuilder<(ins "llvm::StringRef":$op, "mlir::Value":$lhs, "mlir::Value":$rhs), - [{ build($_builder, $_state, $_builder.getType(), op, lhs, rhs); }]>, - ]; -} - -def CallOp : Cxx_Op<"call"> { - let arguments = (ins Cxx_ExprType:$callee, Variadic:$arguments); - let results = (outs Cxx_ExprType:$result); - let assemblyFormat = "$callee `(` $arguments `:` type($arguments) `)` attr-dict `:` type($result)"; - let builders = [ - OpBuilder<(ins "mlir::Value":$callee, "mlir::ValueRange":$arguments), - [{ build($_builder, $_state, $_builder.getType(), callee, arguments); }]>, + let assemblyFormat = + "`op` $op `(` $lhs `,` $rhs `)` attr-dict `:` type($result)"; + let builders = + [OpBuilder< + (ins "llvm::StringRef":$op, "mlir::Value":$lhs, "mlir::Value":$rhs), + [{ build($_builder, $_state, $_builder.getType(), op, lhs, rhs); }]>, ]; } - -def ReturnOp : Cxx_Op<"return"> { - let arguments = (ins Optional:$value); - let results = (outs); -} \ No newline at end of file diff --git a/src/mlir/cxx/mlir/codegen.cc b/src/mlir/cxx/mlir/codegen.cc index 5bc85e64..9fe2f9fa 100644 --- a/src/mlir/cxx/mlir/codegen.cc +++ b/src/mlir/cxx/mlir/codegen.cc @@ -670,7 +670,16 @@ auto Codegen::operator()(UnitAST* ast) -> UnitResult { } auto Codegen::operator()(DeclarationAST* ast) -> DeclarationResult { - if (ast) return visit(DeclarationVisitor{*this}, ast); + // 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); + } + return {}; } @@ -1024,21 +1033,9 @@ auto Codegen::UnitVisitor::operator()(TranslationUnitAST* ast) -> UnitResult { std::swap(gen.module_, module); -#if false for (auto node : ListView{ast->declarationList}) { auto value = gen(node); } -#else - for (ASTCursor it(ast, "unit"); it; ++it) { - const auto& current = *it; - if (std::holds_alternative(current.node)) { - auto ast = std::get(current.node); - if (auto funDecl = ast_cast(ast)) { - auto function = gen(funDecl); - } - } - } -#endif std::swap(gen.module_, module); @@ -1071,6 +1068,7 @@ auto Codegen::UnitVisitor::operator()(ModuleUnitAST* ast) -> UnitResult { auto Codegen::DeclarationVisitor::operator()(SimpleDeclarationAST* ast) -> DeclarationResult { +#if false for (auto node : ListView{ast->attributeList}) { auto value = gen(node); } @@ -1084,6 +1082,7 @@ auto Codegen::DeclarationVisitor::operator()(SimpleDeclarationAST* ast) } auto requiresClauseResult = gen(ast->requiresClause); +#endif return {}; } @@ -1193,8 +1192,22 @@ auto Codegen::DeclarationVisitor::operator()(OpaqueEnumDeclarationAST* ast) auto Codegen::DeclarationVisitor::operator()(FunctionDefinitionAST* ast) -> DeclarationResult { + auto functionSymbol = ast->symbol; + auto functionType = type_cast(functionSymbol->type()); + + auto exprType = gen.builder_.getType(); + std::vector inputTypes; std::vector resultTypes; + + for (auto paramTy : functionType->parameterTypes()) { + inputTypes.push_back(exprType); + } + + if (!gen.control()->is_void(functionType->returnType())) { + resultTypes.push_back(exprType); + } + auto funcType = gen.builder_.getFunctionType(inputTypes, resultTypes); auto loc = gen.builder_.getUnknownLoc(); @@ -1206,19 +1219,26 @@ auto Codegen::DeclarationVisitor::operator()(FunctionDefinitionAST* ast) } std::string name; - 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_); + 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_); + } auto savedInsertionPoint = gen.builder_.saveInsertionPoint(); - auto func = gen.builder_.create(loc, name, funcType); + auto func = gen.builder_.create(loc, name, funcType); - auto entryBlock = gen.builder_.createBlock(&func.getBody()); + auto entryBlock = &func.front(); gen.builder_.setInsertionPointToEnd(entryBlock); @@ -1241,7 +1261,17 @@ auto Codegen::DeclarationVisitor::operator()(FunctionDefinitionAST* ast) std::swap(gen.function_, func); - gen.builder_.create(gen.builder_.getUnknownLoc()); + auto endLoc = gen.getLocation(ast->lastSourceLocation()); + + if (gen.control()->is_void(functionType->returnType())) { + // If the function returns void, we don't need to return anything. + gen.builder_.create(endLoc); + } else { + // Otherwise, we need to return a value of the correct type. + auto r = gen.emitTodoExpr(ast->lastSourceLocation(), "result value"); + auto result = + gen.builder_.create(endLoc, r->getResults()); + } gen.builder_.restoreInsertionPoint(savedInsertionPoint); @@ -1422,23 +1452,27 @@ auto Codegen::DeclarationVisitor::operator()(AsmGotoLabelAST* ast) } void Codegen::StatementVisitor::operator()(LabeledStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "LabeledStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); } void Codegen::StatementVisitor::operator()(CaseStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "CaseStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); + +#if false auto expressionResult = gen.expression(ast->expression); +#endif } void Codegen::StatementVisitor::operator()(DefaultStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "DefaultStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); } void Codegen::StatementVisitor::operator()(ExpressionStatementAST* ast) { - auto op = - gen.emitTodoStmt(ast->firstSourceLocation(), "ExpressionStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false auto expressionResult = gen.expression(ast->expression); +#endif } void Codegen::StatementVisitor::operator()(CompoundStatementAST* ast) { @@ -1448,127 +1482,122 @@ void Codegen::StatementVisitor::operator()(CompoundStatementAST* ast) { } void Codegen::StatementVisitor::operator()(IfStatementAST* ast) { - gen.statement(ast->initializer); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false + gen.statement(ast->initializer); auto conditionResult = gen.expression(ast->condition); - - auto condition = gen.builder_.create( - gen.getLocation(ast->ifLoc), gen.builder_.getI1Type(), - conditionResult.value); - - auto ifOp = gen.builder_.create(gen.getLocation(ast->ifLoc), - condition, - /*withElse=*/true); - - auto ip = gen.builder_.saveInsertionPoint(); - - if (ast->statement) { - gen.builder_.setInsertionPointToStart(&ifOp.getThenRegion().front()); - gen.statement(ast->statement); - } - - if (ast->elseStatement) { - gen.builder_.setInsertionPointToStart(&ifOp.getElseRegion().front()); - gen.statement(ast->elseStatement); - } - - gen.builder_.restoreInsertionPoint(ip); + gen.statement(ast->statement); + gen.statement(ast->elseStatement); +#endif } void Codegen::StatementVisitor::operator()(ConstevalIfStatementAST* ast) { - auto op = - gen.emitTodoStmt(ast->firstSourceLocation(), "ConstevalIfStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false gen.statement(ast->statement); gen.statement(ast->elseStatement); +#endif } void Codegen::StatementVisitor::operator()(SwitchStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "SwitchStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false gen.statement(ast->initializer); auto conditionResult = gen.expression(ast->condition); gen.statement(ast->statement); +#endif } void Codegen::StatementVisitor::operator()(WhileStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "WhileStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false auto conditionResult = gen.expression(ast->condition); gen.statement(ast->statement); +#endif } void Codegen::StatementVisitor::operator()(DoStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "DoStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false gen.statement(ast->statement); auto expressionResult = gen.expression(ast->expression); +#endif } void Codegen::StatementVisitor::operator()(ForRangeStatementAST* ast) { - auto op = - gen.emitTodoStmt(ast->firstSourceLocation(), "ForRangeStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false gen.statement(ast->initializer); auto rangeDeclarationResult = gen(ast->rangeDeclaration); auto rangeInitializerResult = gen.expression(ast->rangeInitializer); gen.statement(ast->statement); +#endif } void Codegen::StatementVisitor::operator()(ForStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "ForStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false gen.statement(ast->initializer); auto conditionResult = gen.expression(ast->condition); auto expressionResult = gen.expression(ast->expression); gen.statement(ast->statement); +#endif } void Codegen::StatementVisitor::operator()(BreakStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "BreakStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); } void Codegen::StatementVisitor::operator()(ContinueStatementAST* ast) { - auto op = - gen.emitTodoStmt(ast->firstSourceLocation(), "ContinueStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); } void Codegen::StatementVisitor::operator()(ReturnStatementAST* ast) { - auto expressionResult = gen.expression(ast->expression); - - auto loc = gen.getLocation(ast->firstSourceLocation()); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); - auto op = - gen.builder_.create(loc, expressionResult.value); +#if false + auto expressionResult = gen.expression(ast->expression); +#endif } void Codegen::StatementVisitor::operator()(CoroutineReturnStatementAST* ast) { auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "CoroutineReturnStatementAST"); +#if false auto expressionResult = gen.expression(ast->expression); +#endif } void Codegen::StatementVisitor::operator()(GotoStatementAST* ast) { - auto op = gen.emitTodoStmt(ast->firstSourceLocation(), "GotoStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); } void Codegen::StatementVisitor::operator()(DeclarationStatementAST* ast) { - auto op = - gen.emitTodoStmt(ast->firstSourceLocation(), "DeclarationStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false auto declarationResult = gen(ast->declaration); +#endif } void Codegen::StatementVisitor::operator()(TryBlockStatementAST* ast) { - auto op = - gen.emitTodoStmt(ast->firstSourceLocation(), "TryBlockStatementAST"); + (void)gen.emitTodoStmt(ast->firstSourceLocation(), to_string(ast->kind())); +#if false gen.statement(ast->statement); for (auto node : ListView{ast->handlerList}) { auto value = gen(node); } +#endif } auto Codegen::ExpressionVisitor::operator()(GeneratedLiteralExpressionAST* ast) diff --git a/src/mlir/cxx/mlir/codegen.h b/src/mlir/cxx/mlir/codegen.h index 37e70d3f..3f0513ba 100644 --- a/src/mlir/cxx/mlir/codegen.h +++ b/src/mlir/cxx/mlir/codegen.h @@ -196,7 +196,7 @@ class Codegen { mlir::OpBuilder builder_; mlir::ModuleOp module_; - mlir::func::FuncOp function_; + mlir::cxx::FuncOp function_; TranslationUnit* unit_ = nullptr; int count_ = 0; }; diff --git a/src/mlir/cxx/mlir/cxx_dialect.cc b/src/mlir/cxx/mlir/cxx_dialect.cc index 6c1f2dad..927d37c3 100644 --- a/src/mlir/cxx/mlir/cxx_dialect.cc +++ b/src/mlir/cxx/mlir/cxx_dialect.cc @@ -27,6 +27,8 @@ #include #include #include +#include +#include namespace mlir::cxx { @@ -42,6 +44,32 @@ void CxxDialect::initialize() { >(); } +void FuncOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, + llvm::StringRef name, mlir::FunctionType type, + llvm::ArrayRef attrs) { + buildWithEntryBlock(builder, state, name, type, attrs, type.getInputs()); +} + +void FuncOp::print(mlir::OpAsmPrinter &p) { + mlir::function_interface_impl::printFunctionOp( + p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(), + getArgAttrsAttrName(), getResAttrsAttrName()); +} + +auto FuncOp::parse(mlir::OpAsmParser &parser, mlir::OperationState &result) + -> mlir::ParseResult { + auto funcTypeBuilder = + [](mlir::Builder &builder, llvm::ArrayRef argTypes, + llvm::ArrayRef results, + mlir::function_interface_impl::VariadicFlag, + std::string &) { return builder.getFunctionType(argTypes, results); }; + + return mlir::function_interface_impl::parseFunctionOp( + parser, result, false, getFunctionTypeAttrName(result.name), + funcTypeBuilder, getArgAttrsAttrName(result.name), + getResAttrsAttrName(result.name)); +} + } // namespace mlir::cxx #define GET_TYPEDEF_CLASSES diff --git a/src/mlir/cxx/mlir/cxx_dialect.h b/src/mlir/cxx/mlir/cxx_dialect.h index b6dc72d4..df01cea7 100644 --- a/src/mlir/cxx/mlir/cxx_dialect.h +++ b/src/mlir/cxx/mlir/cxx_dialect.h @@ -26,6 +26,13 @@ #endif #include +#include +#include +#include +#include +#include +#include +#include #if defined(__clang__) || defined(__GNUC__) #pragma GCC diagnostic pop diff --git a/src/parser/cxx/binder.cc b/src/parser/cxx/binder.cc index 8ef96ead..8d104db3 100644 --- a/src/parser/cxx/binder.cc +++ b/src/parser/cxx/binder.cc @@ -599,6 +599,11 @@ auto Binder::declareFunction(DeclaratorAST* declarator, const Decl& decl) } auto functionSymbol = control()->newFunctionSymbol(scope(), decl.location()); + + if (is_parsing_c()) { + functionSymbol->setHasCxxLinkage(false); + } + applySpecifiers(functionSymbol, decl.specs); functionSymbol->setName(name); functionSymbol->setType(type); diff --git a/src/parser/cxx/cli.cc b/src/parser/cxx/cli.cc index 691447fc..639485ae 100644 --- a/src/parser/cxx/cli.cc +++ b/src/parser/cxx/cli.cc @@ -136,6 +136,9 @@ std::vector options{ {"-c", "Compile and assemble, but do not link", &CLI::opt_c, CLIOptionVisibility::kExperimental}, + {"-g", "Generate debug information", &CLI::opt_g, + CLIOptionVisibility::kExperimental}, + {"-o", "", "Place output into ", CLIOptionDescrKind::kSeparated}, diff --git a/src/parser/cxx/cli.h b/src/parser/cxx/cli.h index 1177b313..c20fe83e 100644 --- a/src/parser/cxx/cli.h +++ b/src/parser/cxx/cli.h @@ -75,6 +75,7 @@ class CLI { bool opt_emit_ast = false; bool opt_lsp = false; bool opt_lsp_test = false; + bool opt_g = false; void parse(int& argc, char**& argv); diff --git a/src/parser/cxx/symbols.cc b/src/parser/cxx/symbols.cc index e8ef097c..1eb06024 100644 --- a/src/parser/cxx/symbols.cc +++ b/src/parser/cxx/symbols.cc @@ -462,6 +462,14 @@ auto FunctionSymbol::isConstructor() const -> bool { return true; } +auto FunctionSymbol::hasCLinkage() const -> bool { return isExternC_; } + +auto FunctionSymbol::hasCxxLinkage() const -> bool { return !isExternC_; } + +void FunctionSymbol::setHasCxxLinkage(bool hasCxxLinkage) { + isExternC_ = !hasCxxLinkage; +} + OverloadSetSymbol::OverloadSetSymbol(Scope* enclosingScope) : Symbol(Kind, enclosingScope) {} diff --git a/src/parser/cxx/symbols.h b/src/parser/cxx/symbols.h index 966b0f5f..f11f2441 100644 --- a/src/parser/cxx/symbols.h +++ b/src/parser/cxx/symbols.h @@ -416,6 +416,10 @@ class FunctionSymbol final : public ScopedSymbol { [[nodiscard]] auto isConstructor() const -> bool; + [[nodiscard]] auto hasCLinkage() const -> bool; + [[nodiscard]] auto hasCxxLinkage() const -> bool; + void setHasCxxLinkage(bool hasCLinkage); + private: TemplateParametersSymbol* templateParameters_ = nullptr; @@ -433,6 +437,7 @@ class FunctionSymbol final : public ScopedSymbol { std::uint32_t isExplicit_ : 1; std::uint32_t isDeleted_ : 1; std::uint32_t isDefaulted_ : 1; + std::uint32_t isExternC_ : 1; }; }; };