Sfoglia il codice sorgente

Add support for macros evaluating to an enum constant (#6432)

Enum constants in a macro replacement list are recognized only when
prefixed with “::”.
There is a `todo` test to make explicit that this still needs to be
fixed.
When prefixed with a global scope “::”, they are correctly found and
evaluated to a const.


Part of #6303
Ivana Ivanovska 5 mesi fa
parent
commit
cf2c66c1b2

+ 7 - 0
toolchain/check/cpp/macros.cpp

@@ -25,6 +25,7 @@ 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(),
@@ -45,7 +46,12 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
                                 /*IsReinject=*/false);
   parser.ConsumeAnyToken(true);
 
+  // TODO: Identifiers are still only available if prefixed with "::" (e.g.
+  // "#define M_Var ::myVar").
+  parser.EnterScope(clang::Scope::DeclScope);
   clang::ExprResult result = parser.ParseConstantExpression();
+  parser.ExitScope();
+
   clang::Expr* result_expr = result.get();
 
   bool success =
@@ -70,6 +76,7 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
   clang::Expr::EvalResult evaluated_result;
   CARBON_CHECK(result_expr->EvaluateAsConstantExpr(evaluated_result,
                                                    sema.getASTContext()));
+
   clang::APValue ap_value = evaluated_result.Val;
   switch (ap_value.getKind()) {
     case clang::APValue::Int:

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

@@ -608,6 +608,42 @@ fn F() {
   Cpp.foo(Cpp.MyNullPtr);
 }
 
+// --- enums.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp inline '''
+  enum A { a = 1, b = 2 };
+  #define M_A ::a
+''';
+
+fn F() {
+  let a: Cpp.A = Cpp.M_A;
+}
+
+// --- fail_todo_enums_no_scope.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp inline '''
+  enum A { a = 1, b = 2 };
+  // CHECK:STDERR: fail_todo_enums_no_scope.carbon:[[@LINE+7]]:24: error: use of undeclared identifier 'a'; did you mean '::a'? [CppInteropParseError]
+  // CHECK:STDERR:    13 |   #define M_A_NO_SCOPE a
+  // CHECK:STDERR:       |                        ^
+  // CHECK:STDERR:       |                        ::a
+  // CHECK:STDERR: fail_todo_enums_no_scope.carbon:[[@LINE-5]]:12: note: '::a' declared here [CppInteropParseNote]
+  // CHECK:STDERR:     5 |   enum A { a = 1, b = 2 };
+  // CHECK:STDERR:       |            ^
+  #define M_A_NO_SCOPE a
+''';
+
+fn F() {
+  // CHECK:STDERR: fail_todo_enums_no_scope.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `M_A_NO_SCOPE` [InCppNameLookup]
+  // CHECK:STDERR:   Cpp.M_A_NO_SCOPE;
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  Cpp.M_A_NO_SCOPE;
+}
 
 // --- lambda.carbon