Преглед изворни кода

Add support for macros pointing to a constexpr integer (#6441)

Similarly to the enums, these are for the moment only available when
referenced with a global scope “::”. Only integer constexpr are
available for now.

Part of #6303
Ivana Ivanovska пре 5 месеци
родитељ
комит
4ddff65e8e
2 измењених фајлова са 112 додато и 1 уклоњено
  1. 12 1
      toolchain/check/cpp/macros.cpp
  2. 100 0
      toolchain/check/testdata/interop/cpp/macros.carbon

+ 12 - 1
toolchain/check/cpp/macros.cpp

@@ -25,7 +25,6 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
 
   clang::Sema& sema = context.clang_sema();
   clang::Preprocessor& preprocessor = sema.getPreprocessor();
-
   clang::Parser parser(preprocessor, sema, false);
 
   llvm::SmallVector<clang::Token> tokens(macro_info->tokens().begin(),
@@ -67,6 +66,8 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
     return nullptr;
   }
 
+  result_expr = result_expr->IgnoreParenImpCasts();
+
   if (isa<clang::StringLiteral>(result_expr) ||
       isa<clang::CharacterLiteral>(result_expr) ||
       isa<clang::CXXNullPtrLiteralExpr>(result_expr)) {
@@ -78,6 +79,16 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
                                                    sema.getASTContext()));
 
   clang::APValue ap_value = evaluated_result.Val;
+  // TODO: Add support for other types.
+  if (ap_value.isLValue()) {
+    if (!result_expr->EvaluateAsInt(evaluated_result, sema.getASTContext())) {
+      context.TODO(loc_id,
+                   "Unsupported: macro evaluated to a non-integer LValue");
+      return nullptr;
+    }
+    ap_value = evaluated_result.Val;
+  }
+
   switch (ap_value.getKind()) {
     case clang::APValue::Int:
       if (result_expr->getType()->isBooleanType()) {

+ 100 - 0
toolchain/check/testdata/interop/cpp/macros.carbon

@@ -681,6 +681,69 @@ fn F() {
   Cpp.M_A_NO_SCOPE;
 }
 
+// --- constexpr_int.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp inline '''
+   constexpr int a = 1;
+   #define M_CONSTEXPR_INT ::a
+''';
+
+fn F() {
+  //@dump-sem-ir-begin
+  let a: i32 = Cpp.M_CONSTEXPR_INT;
+  //@dump-sem-ir-end
+}
+
+// --- fail_import_constexpr_no_scope.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp inline '''
+   constexpr int a = 1;
+   // CHECK:STDERR: fail_import_constexpr_no_scope.carbon:[[@LINE+7]]:33: error: use of undeclared identifier 'a'; did you mean '::a'? [CppInteropParseError]
+   // CHECK:STDERR:    13 |    #define M_CONSTEXPR_NO_SCOPE a
+   // CHECK:STDERR:       |                                 ^
+   // CHECK:STDERR:       |                                 ::a
+   // CHECK:STDERR: fail_import_constexpr_no_scope.carbon:[[@LINE-5]]:18: note: '::a' declared here [CppInteropParseNote]
+   // CHECK:STDERR:     5 |    constexpr int a = 1;
+   // CHECK:STDERR:       |                  ^
+   #define M_CONSTEXPR_NO_SCOPE a
+''';
+
+fn F() {
+  // CHECK:STDERR: fail_import_constexpr_no_scope.carbon:[[@LINE+4]]:16: note: in `Cpp` name lookup for `M_CONSTEXPR_NO_SCOPE` [InCppNameLookup]
+  // CHECK:STDERR:   let a: i32 = Cpp.M_CONSTEXPR_NO_SCOPE;
+  // CHECK:STDERR:                ^~~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  let a: i32 = Cpp.M_CONSTEXPR_NO_SCOPE;
+}
+
+// --- fail_todo_import_macro_constexpr_float.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp inline '''
+   constexpr float b = 1.0f;
+   #define M_CONSTEXPR_FLOAT ::b
+''';
+
+fn F() {
+  // CHECK:STDERR: fail_todo_import_macro_constexpr_float.carbon:[[@LINE+11]]:16: error: semantics TODO: `Unsupported: macro evaluated to a non-integer LValue` [SemanticsTodo]
+  // CHECK:STDERR:   let a: f32 = Cpp.M_CONSTEXPR_FLOAT;
+  // CHECK:STDERR:                ^~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_todo_import_macro_constexpr_float.carbon:[[@LINE+8]]:16: note: in `Cpp` name lookup for `M_CONSTEXPR_FLOAT` [InCppNameLookup]
+  // CHECK:STDERR:   let a: f32 = Cpp.M_CONSTEXPR_FLOAT;
+  // CHECK:STDERR:                ^~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  // CHECK:STDERR: fail_todo_import_macro_constexpr_float.carbon:[[@LINE+4]]:16: error: member name `M_CONSTEXPR_FLOAT` not found in `Cpp` [MemberNameNotFoundInInstScope]
+  // CHECK:STDERR:   let a: f32 = Cpp.M_CONSTEXPR_FLOAT;
+  // CHECK:STDERR:                ^~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  let a: f32 = Cpp.M_CONSTEXPR_FLOAT;
+}
+
 // --- lambda.carbon
 
 library "[[@TEST_NAME]]";
@@ -1828,6 +1891,43 @@ fn F() {
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: --- constexpr_int.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:   %const: type = const_type %i32 [concrete]
+// CHECK:STDOUT:   %int_1.22e: %const = int_value 1 [concrete]
+// CHECK:STDOUT:   %int_1.5d2: %i32 = int_value 1 [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
+// CHECK:STDOUT:     .M_CONSTEXPR_INT = %int_1
+// CHECK:STDOUT:     import Cpp//...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %int_1: %const = int_value 1 [concrete = constants.%int_1.22e]
+// 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   <elided>
+// CHECK:STDOUT:   %M_CONSTEXPR_INT.ref: %const = name_ref M_CONSTEXPR_INT, imports.%int_1 [concrete = constants.%int_1.22e]
+// CHECK:STDOUT:   %.loc11_10: 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:   %.loc11_19.1: %i32 = as_compatible %M_CONSTEXPR_INT.ref [concrete = constants.%int_1.5d2]
+// CHECK:STDOUT:   %.loc11_19.2: %i32 = converted %M_CONSTEXPR_INT.ref, %.loc11_19.1 [concrete = constants.%int_1.5d2]
+// CHECK:STDOUT:   %a: %i32 = value_binding a, %.loc11_19.2
+// CHECK:STDOUT:   <elided>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- lambda.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {