From b68b6ae1e7b09f2610f93dd37d5535096d8e58c2 Mon Sep 17 00:00:00 2001 From: Ivana Ivanovska Date: Wed, 12 Nov 2025 18:06:39 +0100 Subject: [PATCH] Add support for more complex object-like macros (#6338) Uses `clang::Parser::ParseConstantExpression()` to parse the macro replacement tokens, added as a token stream to the preprocessor. This extends the support from simple object-like macros with a single replacement token, to multiple tokens like unary operators, binary operators, casting, nested macros etc. The support is still limited to macros that are evaluated to an integer constant. More types to be added as a follow-up. Part of #6303 --- toolchain/check/BUILD | 1 + toolchain/check/cpp/macros.cpp | 54 ++- toolchain/check/cpp/macros.h | 5 +- .../check/testdata/interop/cpp/macros.carbon | 356 ++++++++++++++++-- 4 files changed, 365 insertions(+), 51 deletions(-) diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 0dfd69cffc43..04566875ed1e 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -165,6 +165,7 @@ cc_library( "@llvm-project//clang:basic", "@llvm-project//clang:frontend", "@llvm-project//clang:lex", + "@llvm-project//clang:parse", "@llvm-project//clang:sema", "@llvm-project//clang:tooling", "@llvm-project//llvm:Support", diff --git a/toolchain/check/cpp/macros.cpp b/toolchain/check/cpp/macros.cpp index 7072e9c47130..42c7b9495f78 100644 --- a/toolchain/check/cpp/macros.cpp +++ b/toolchain/check/cpp/macros.cpp @@ -5,6 +5,8 @@ #include "toolchain/check/cpp/macros.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/Parse/Parser.h" #include "clang/Sema/Sema.h" namespace Carbon::Check { @@ -14,24 +16,41 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id, clang::MacroInfo* macro_info) -> clang::Expr* { auto name_str_opt = context.names().GetAsStringIfIdentifier(name_id); CARBON_CHECK(macro_info, "macro info missing"); - if (macro_info->getNumTokens() != 1) { - context.TODO(loc_id, - llvm::formatv("Unsupported: macro with {0} replacement tokens", - macro_info->getNumTokens())); - return nullptr; - } - const clang::Token& tok = macro_info->getReplacementToken(0); - if (!tok.is(clang::tok::numeric_constant)) { - context.TODO(loc_id, - "Unsupported: macro replacement token kind: " + - std::string(clang::tok::getTokenName(tok.getKind()))); + + if (macro_info->getNumTokens() == 0) { + context.TODO(loc_id, "Unsupported: macro with 0 replacement tokens"); return nullptr; } + clang::Sema& sema = context.clang_sema(); - clang::ExprResult result = sema.ActOnNumericConstant(tok); + clang::Preprocessor& preprocessor = sema.getPreprocessor(); + clang::Parser parser(preprocessor, sema, false); + + llvm::SmallVector tokens(macro_info->tokens().begin(), + macro_info->tokens().end()); + + clang::Token current_token = parser.getCurToken(); + + // Add eof token + clang::Token eof; + eof.startToken(); + eof.setKind(clang::tok::eof); + eof.setLocation(current_token.getEndLoc()); + tokens.push_back(eof); + + tokens.push_back(current_token); + + preprocessor.EnterTokenStream(tokens, false, false); + parser.ConsumeAnyToken(true); + + clang::ExprResult result = parser.ParseConstantExpression(); clang::Expr* result_expr = result.get(); - if (!result_expr || result.isInvalid()) { + bool success = + !result.isInvalid() && parser.getCurToken().is(clang::tok::eof); + + if (!success) { + parser.SkipUntil(clang::tok::eof); CARBON_DIAGNOSTIC( InCppMacroEvaluation, Error, "failed to evaluate macro Cpp.{0} to a valid constant expression", @@ -40,7 +59,14 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id, return nullptr; } - return result_expr; + clang::Expr::EvalResult evaluated_result; + if (!result_expr->EvaluateAsInt(evaluated_result, sema.getASTContext())) { + context.TODO(loc_id, "non-integer constant expression in macro."); + return nullptr; + } + return clang::IntegerLiteral::Create( + sema.getASTContext(), evaluated_result.Val.getInt(), + result_expr->getType(), result_expr->getExprLoc()); } } // namespace Carbon::Check diff --git a/toolchain/check/cpp/macros.h b/toolchain/check/cpp/macros.h index 286bb019362c..6c999559fd2b 100644 --- a/toolchain/check/cpp/macros.h +++ b/toolchain/check/cpp/macros.h @@ -11,9 +11,8 @@ namespace Carbon::Check { // Tries to evaluate the given macro to a constant expression. Returns the // evaluated expression on success or nullptr otherwise. Currently supports only -// simple object-like macros with a single replacement token that is a numeric -// literal token. -// TODO: Add support for multiple tokens and other literal types. +// object-like macros that evaluate to an integer constant. +// TODO: Add support for other literal types. auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id, SemIR::NameId name_id, clang::MacroInfo* macro_info) -> clang::Expr*; diff --git a/toolchain/check/testdata/interop/cpp/macros.carbon b/toolchain/check/testdata/interop/cpp/macros.carbon index bf3b2b1dfa8f..fe99bf92acb3 100644 --- a/toolchain/check/testdata/interop/cpp/macros.carbon +++ b/toolchain/check/testdata/interop/cpp/macros.carbon @@ -186,29 +186,71 @@ fn F() { Cpp.MACRO_NAME; } -// --- multiple_replacement_tokens_object_like_macro.h -#define CONFIG_VALUE 1+2 +// --- unary_operator.h +#define NEGATIVE -1 -// --- fail_todo_import_multiple_replacement_tokens_object_like_macro.carbon +// --- import_unary_operator.carbon library "[[@TEST_NAME]]"; -import Cpp library "multiple_replacement_tokens_object_like_macro.h"; +import Cpp library "unary_operator.h"; fn F() { - // TODO: Get rid of the second error. - // CHECK:STDERR: fail_todo_import_multiple_replacement_tokens_object_like_macro.carbon:[[@LINE+11]]:16: error: semantics TODO: `Unsupported: macro with 3 replacement tokens` [SemanticsTodo] - // CHECK:STDERR: let a: i32 = Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_multiple_replacement_tokens_object_like_macro.carbon:[[@LINE+8]]:16: note: in `Cpp` name lookup for `CONFIG_VALUE` [InCppNameLookup] - // CHECK:STDERR: let a: i32 = Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_multiple_replacement_tokens_object_like_macro.carbon:[[@LINE+4]]:16: error: member name `CONFIG_VALUE` not found in `Cpp` [MemberNameNotFoundInInstScope] - // CHECK:STDERR: let a: i32 = Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: - let a: i32 = Cpp.CONFIG_VALUE; + //@dump-sem-ir-begin + let a: i32 = Cpp.NEGATIVE; + //@dump-sem-ir-end +} + +// --- binary_operator.h +#define ADDITION 1+2 + +// --- import_binary_operator.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "binary_operator.h"; + +fn F() { + //@dump-sem-ir-begin + let a: i32 = Cpp.ADDITION; + //@dump-sem-ir-end +} + +// --- casting.h +#define CAST_UNSIGNED (unsigned int)1 +#define CAST_STATIC static_cast(100.5) +#define CAST_FUNCTIONAL int(99.9) +#define CAST_BOOL_TO_INT (int)true + +// --- import_casting.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "casting.h"; + +fn F() { + //@dump-sem-ir-begin + let a: u32 = Cpp.CAST_UNSIGNED; + let b: i32 = Cpp.CAST_STATIC; + let c: i32 = Cpp.CAST_FUNCTIONAL; + let d: i32 = Cpp.CAST_BOOL_TO_INT; + //@dump-sem-ir-end +} + +// --- nested_macros.h +#define ONE 1 +#define INDIRECT_ONE ONE + +// --- import_nested_macros.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "nested_macros.h"; + +fn F() { + //@dump-sem-ir-begin + let a: i32 = Cpp.INDIRECT_ONE; + //@dump-sem-ir-end } // --- string_literal_object_like_macro.h @@ -222,7 +264,7 @@ import Cpp library "string_literal_object_like_macro.h"; fn F() { // TODO: Get rid of the second error. - // CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+11]]:3: error: semantics TODO: `Unsupported: macro replacement token kind: string_literal` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+11]]:3: error: semantics TODO: `non-integer constant expression in macro.` [SemanticsTodo] // CHECK:STDERR: Cpp.CONFIG_VALUE; // CHECK:STDERR: ^~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `CONFIG_VALUE` [InCppNameLookup] @@ -247,7 +289,7 @@ import Cpp library "floating_point_literal_macro.h"; fn F() { // TODO: Get rid of the second error. - // CHECK:STDERR: fail_todo_floating_point_literal_macro.carbon:[[@LINE+11]]:16: error: semantics TODO: `Unsupported: constant type: double` [SemanticsTodo] + // CHECK:STDERR: fail_todo_floating_point_literal_macro.carbon:[[@LINE+11]]:16: error: semantics TODO: `non-integer constant expression in macro.` [SemanticsTodo] // CHECK:STDERR: let a: f64 = Cpp.PI; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: fail_todo_floating_point_literal_macro.carbon:[[@LINE+8]]:16: note: in `Cpp` name lookup for `PI` [InCppNameLookup] @@ -273,19 +315,19 @@ library "[[@TEST_NAME]]"; import Cpp library "macro_undefined.h"; fn F() { - // CHECK:STDERR: fail_macro_undefined.carbon:[[@LINE+4]]:15: error: member name `CONFIG_VALUE` not found in `Cpp` [MemberNameNotFoundInInstScope] - // CHECK:STDERR: let a: i32 = Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: - let a: i32 = Cpp.CONFIG_VALUE; + // CHECK:STDERR: fail_macro_undefined.carbon:[[@LINE+4]]:16: error: member name `CONFIG_VALUE` not found in `Cpp` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: let a: i32 = Cpp.CONFIG_VALUE; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: + let a: i32 = Cpp.CONFIG_VALUE; } // --- macro_redefined.h -#define CONFIG_VALUE 1 -#undef CONFIG_VALUE +#define REDEF_NAME 1 +#undef REDEF_NAME -#define CONFIG_VALUE 2 +#define REDEF_NAME 2 // --- import_macro_redefined.carbon @@ -294,31 +336,35 @@ library "[[@TEST_NAME]]"; import Cpp library "macro_redefined.h"; fn F() { - let a: i32 = Cpp.CONFIG_VALUE; + //@dump-sem-ir-begin + let a: i32 = Cpp.REDEF_NAME; + //@dump-sem-ir-end } // --- macro_defined_twice.h -#define CONFIG_VALUE 1 -#define CONFIG_VALUE 2 +#define TWICE_DEF 1 +#define TWICE_DEF 2 // --- import_macro_defined_twice.carbon library "[[@TEST_NAME]]"; // CHECK:STDERR: import_macro_defined_twice.carbon:[[@LINE+9]]:10: in file included here [InCppInclude] -// CHECK:STDERR: ./macro_defined_twice.h:3:9: warning: 'CONFIG_VALUE' macro redefined [CppInteropParseWarning] -// CHECK:STDERR: 3 | #define CONFIG_VALUE 2 +// CHECK:STDERR: ./macro_defined_twice.h:3:9: warning: 'TWICE_DEF' macro redefined [CppInteropParseWarning] +// CHECK:STDERR: 3 | #define TWICE_DEF 2 // CHECK:STDERR: | ^ // CHECK:STDERR: import_macro_defined_twice.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./macro_defined_twice.h:2:9: note: previous definition is here [CppInteropParseNote] -// CHECK:STDERR: 2 | #define CONFIG_VALUE 1 +// CHECK:STDERR: 2 | #define TWICE_DEF 1 // CHECK:STDERR: | ^ // CHECK:STDERR: import Cpp library "macro_defined_twice.h"; fn F() { - let a: i32 = Cpp.CONFIG_VALUE; + //@dump-sem-ir-begin + let a: i32 = Cpp.TWICE_DEF; + //@dump-sem-ir-end } // ============================================================================ @@ -500,3 +546,245 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- import_unary_operator.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %int_-1: %i32 = int_value -1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .NEGATIVE = %int_-1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_-1: %i32 = int_value -1 [concrete = constants.%int_-1] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %NEGATIVE.ref: %i32 = name_ref NEGATIVE, imports.%int_-1 [concrete = constants.%int_-1] +// CHECK:STDOUT: %.loc8: type = splice_block %i32.loc8 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc8: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc8: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %i32 = value_binding a, %NEGATIVE.ref +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_binary_operator.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %int_3: %i32 = int_value 3 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .ADDITION = %int_3 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_3: %i32 = int_value 3 [concrete = constants.%int_3] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %ADDITION.ref: %i32 = name_ref ADDITION, imports.%int_3 [concrete = constants.%int_3] +// CHECK:STDOUT: %.loc8: type = splice_block %i32.loc8 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc8: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc8: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %i32 = value_binding a, %ADDITION.ref +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_casting.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %u32: type = class_type @UInt, @UInt(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.4a9: type = pattern_type %u32 [concrete] +// CHECK:STDOUT: %int_1.c1d: %u32 = int_value 1 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %int_100: %i32 = int_value 100 [concrete] +// CHECK:STDOUT: %int_99: %i32 = int_value 99 [concrete] +// CHECK:STDOUT: %int_1.5d2: %i32 = int_value 1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .CAST_UNSIGNED = %int_1.c1d +// CHECK:STDOUT: .CAST_STATIC = %int_100 +// CHECK:STDOUT: .CAST_FUNCTIONAL = %int_99 +// CHECK:STDOUT: .CAST_BOOL_TO_INT = %int_1.5d2 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_1.c1d: %u32 = int_value 1 [concrete = constants.%int_1.c1d] +// CHECK:STDOUT: %int_100: %i32 = int_value 100 [concrete = constants.%int_100] +// CHECK:STDOUT: %int_99: %i32 = int_value 99 [concrete = constants.%int_99] +// CHECK:STDOUT: %int_1.5d2: %i32 = int_value 1 [concrete = constants.%int_1.5d2] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.4a9 = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %CAST_UNSIGNED.ref: %u32 = name_ref CAST_UNSIGNED, imports.%int_1.c1d [concrete = constants.%int_1.c1d] +// CHECK:STDOUT: %.loc8: type = splice_block %u32.loc8 [concrete = constants.%u32] { +// CHECK:STDOUT: %int_32.loc8: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %u32.loc8: type = class_type @UInt, @UInt(constants.%int_32) [concrete = constants.%u32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %u32 = value_binding a, %CAST_UNSIGNED.ref +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.7ce = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %CAST_STATIC.ref: %i32 = name_ref CAST_STATIC, imports.%int_100 [concrete = constants.%int_100] +// CHECK:STDOUT: %.loc9: type = splice_block %i32.loc9 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc9: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc9: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %b: %i32 = value_binding b, %CAST_STATIC.ref +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.7ce = value_binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %CAST_FUNCTIONAL.ref: %i32 = name_ref CAST_FUNCTIONAL, imports.%int_99 [concrete = constants.%int_99] +// CHECK:STDOUT: %.loc10: type = splice_block %i32.loc10 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc10: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc10: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %c: %i32 = value_binding c, %CAST_FUNCTIONAL.ref +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %d.patt: %pattern_type.7ce = value_binding_pattern d [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %CAST_BOOL_TO_INT.ref: %i32 = name_ref CAST_BOOL_TO_INT, imports.%int_1.5d2 [concrete = constants.%int_1.5d2] +// CHECK:STDOUT: %.loc11: type = splice_block %i32.loc11 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc11: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc11: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %d: %i32 = value_binding d, %CAST_BOOL_TO_INT.ref +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_nested_macros.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %int_1: %i32 = int_value 1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .INDIRECT_ONE = %int_1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_1: %i32 = int_value 1 [concrete = constants.%int_1] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %INDIRECT_ONE.ref: %i32 = name_ref INDIRECT_ONE, imports.%int_1 [concrete = constants.%int_1] +// CHECK:STDOUT: %.loc8: type = splice_block %i32.loc8 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc8: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc8: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %i32 = value_binding a, %INDIRECT_ONE.ref +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_macro_redefined.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %int_2: %i32 = int_value 2 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .REDEF_NAME = %int_2 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_2: %i32 = int_value 2 [concrete = constants.%int_2] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %REDEF_NAME.ref: %i32 = name_ref REDEF_NAME, imports.%int_2 [concrete = constants.%int_2] +// CHECK:STDOUT: %.loc8: type = splice_block %i32.loc8 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc8: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc8: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %i32 = value_binding a, %REDEF_NAME.ref +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_macro_defined_twice.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %int_2: %i32 = int_value 2 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .TWICE_DEF = %int_2 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_2: %i32 = int_value 2 [concrete = constants.%int_2] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %TWICE_DEF.ref: %i32 = name_ref TWICE_DEF, imports.%int_2 [concrete = constants.%int_2] +// CHECK:STDOUT: %.loc17: type = splice_block %i32.loc17 [concrete = constants.%i32] { +// CHECK:STDOUT: %int_32.loc17: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc17: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %i32 = value_binding a, %TWICE_DEF.ref +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: