Skip to content

Commit 994e6c9

Browse files
Add support for macros with floating-point literals (#6391)
Adding support for floating-point literals in macros. Part of #6303
1 parent 13dd218 commit 994e6c9

File tree

4 files changed

+179
-39
lines changed

4 files changed

+179
-39
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
#include "llvm/ADT/StringMap.h"
3131
#include "llvm/ADT/StringRef.h"
3232
#include "llvm/Support/raw_ostream.h"
33+
#include "toolchain/base/int.h"
3334
#include "toolchain/base/kind_switch.h"
35+
#include "toolchain/base/value_ids.h"
3436
#include "toolchain/check/call.h"
3537
#include "toolchain/check/class.h"
3638
#include "toolchain/check/context.h"
@@ -2224,29 +2226,46 @@ static auto IsIncompleteClass(Context& context, SemIR::NameScopeId scope_id)
22242226
context.classes().Get(class_decl->class_id).self_type_id);
22252227
}
22262228

2227-
// Maps a Clang constant expression to a Carbon constant. Currently supports
2228-
// only integer constants.
2229+
// Maps a Clang literal expression to a Carbon constant. Currently supports
2230+
// only integer and floating-point literals.
22292231
// TODO: Add support for the other constant types for which a C++ to Carbon type
22302232
// mapping exists.
22312233
static auto MapConstant(Context& context, SemIR::LocId loc_id,
22322234
clang::Expr* expr) -> SemIR::InstId {
22332235
CARBON_CHECK(expr, "empty expression");
2234-
auto* integer_literal = dyn_cast<clang::IntegerLiteral>(expr);
2235-
if (!integer_literal) {
2236-
context.TODO(
2237-
loc_id, "Unsupported: constant type: " + expr->getType().getAsString());
2236+
2237+
SemIR::TypeId type_id = MapType(context, loc_id, expr->getType()).type_id;
2238+
if (!type_id.has_value()) {
2239+
context.TODO(loc_id, llvm::formatv("Unsupported: C++ literal's type `{0}` "
2240+
"could not be mapped to a Carbon type",
2241+
expr->getType().getAsString()));
22382242
return SemIR::ErrorInst::InstId;
22392243
}
2240-
SemIR::TypeId type_id =
2241-
MapType(context, loc_id, integer_literal->getType()).type_id;
2242-
if (!type_id.has_value()) {
2243-
CARBON_DIAGNOSTIC(InCppConstantMapping, Error, "invalid integer type");
2244-
context.emitter().Emit(loc_id, InCppConstantMapping);
2244+
2245+
SemIR::InstId inst_id = SemIR::InstId::None;
2246+
SemIR::ImportIRInstId imported_loc_id =
2247+
AddImportIRInst(context.sem_ir(), expr->getExprLoc());
2248+
2249+
if (auto* integer_literal = dyn_cast<clang::IntegerLiteral>(expr)) {
2250+
IntId int_id =
2251+
context.ints().Add(integer_literal->getValue().getSExtValue());
2252+
inst_id = AddInstInNoBlock(
2253+
context,
2254+
MakeImportedLocIdAndInst<SemIR::IntValue>(
2255+
context, imported_loc_id, {.type_id = type_id, .int_id = int_id}));
2256+
} else if (auto* float_literal = dyn_cast<clang::FloatingLiteral>(expr)) {
2257+
FloatId float_id = context.floats().Add(float_literal->getValue());
2258+
inst_id = AddInstInNoBlock(context,
2259+
MakeImportedLocIdAndInst<SemIR::FloatValue>(
2260+
context, imported_loc_id,
2261+
{.type_id = type_id, .float_id = float_id}));
2262+
} else {
2263+
context.TODO(loc_id, llvm::formatv(
2264+
"Unsupported: C++ constant expression type: '{0}'",
2265+
expr->getType().getAsString()));
22452266
return SemIR::ErrorInst::InstId;
22462267
}
2247-
auto int_id = context.ints().Add(integer_literal->getValue().getSExtValue());
2248-
auto inst_id = AddInstInNoBlock<SemIR::IntValue>(
2249-
context, loc_id, {.type_id = type_id, .int_id = int_id});
2268+
22502269
context.imports().push_back(inst_id);
22512270
return inst_id;
22522271
}

toolchain/check/cpp/macros.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "clang/AST/Expr.h"
99
#include "clang/Parse/Parser.h"
1010
#include "clang/Sema/Sema.h"
11+
#include "common/check.h"
1112

1213
namespace Carbon::Check {
1314

@@ -40,7 +41,8 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
4041

4142
tokens.push_back(current_token);
4243

43-
preprocessor.EnterTokenStream(tokens, false, false);
44+
preprocessor.EnterTokenStream(tokens, /*DisableMacroExpansion=*/false,
45+
/*IsReinject=*/false);
4446
parser.ConsumeAnyToken(true);
4547

4648
clang::ExprResult result = parser.ParseConstantExpression();
@@ -53,20 +55,31 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
5355
parser.SkipUntil(clang::tok::eof);
5456
CARBON_DIAGNOSTIC(
5557
InCppMacroEvaluation, Error,
56-
"failed to evaluate macro Cpp.{0} to a valid constant expression",
58+
"failed to parse macro Cpp.{0} to a valid constant expression",
5759
std::string);
5860
context.emitter().Emit(loc_id, InCppMacroEvaluation, (*name_str_opt).str());
5961
return nullptr;
6062
}
6163

6264
clang::Expr::EvalResult evaluated_result;
63-
if (!result_expr->EvaluateAsInt(evaluated_result, sema.getASTContext())) {
64-
context.TODO(loc_id, "non-integer constant expression in macro.");
65-
return nullptr;
65+
CARBON_CHECK(result_expr->EvaluateAsConstantExpr(evaluated_result,
66+
sema.getASTContext()));
67+
clang::APValue ap_value = evaluated_result.Val;
68+
switch (ap_value.getKind()) {
69+
case clang::APValue::Int:
70+
return clang::IntegerLiteral::Create(
71+
sema.getASTContext(), ap_value.getInt(), result_expr->getType(),
72+
result_expr->getExprLoc());
73+
case clang::APValue::Float:
74+
return clang::FloatingLiteral::Create(
75+
sema.getASTContext(), ap_value.getFloat(),
76+
/*isExact=*/true, result_expr->getType(), result_expr->getExprLoc());
77+
default:
78+
context.TODO(loc_id,
79+
"Unsupported: macro evaluated to a constant of type: " +
80+
result_expr->getType().getAsString());
81+
return nullptr;
6682
}
67-
return clang::IntegerLiteral::Create(
68-
sema.getASTContext(), evaluated_result.Val.getInt(),
69-
result_expr->getType(), result_expr->getExprLoc());
7083
}
7184

7285
} // namespace Carbon::Check

toolchain/check/testdata/interop/cpp/macros.carbon

Lines changed: 125 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn F() {
5757
// CHECK:STDERR: Cpp.CONFIG_VALUE;
5858
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
5959
// CHECK:STDERR:
60-
// CHECK:STDERR: fail_import_bad_suffix.carbon:[[@LINE+11]]:3: error: failed to evaluate macro Cpp.CONFIG_VALUE to a valid constant expression [InCppMacroEvaluation]
60+
// CHECK:STDERR: fail_import_bad_suffix.carbon:[[@LINE+11]]:3: error: failed to parse macro Cpp.CONFIG_VALUE to a valid constant expression [InCppMacroEvaluation]
6161
// CHECK:STDERR: Cpp.CONFIG_VALUE;
6262
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
6363
// CHECK:STDERR: fail_import_bad_suffix.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `CONFIG_VALUE` [InCppNameLookup]
@@ -89,7 +89,7 @@ fn F() {
8989
// CHECK:STDERR: Cpp.CONFIG_VALUE;
9090
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
9191
// CHECK:STDERR:
92-
// CHECK:STDERR: fail_import_integer_literal_too_big.carbon:[[@LINE+11]]:3: error: invalid integer type [InCppConstantMapping]
92+
// CHECK:STDERR: fail_import_integer_literal_too_big.carbon:[[@LINE+11]]:3: error: semantics TODO: `Unsupported: C++ literal's type `unsigned long long` could not be mapped to a Carbon type` [SemanticsTodo]
9393
// CHECK:STDERR: Cpp.CONFIG_VALUE;
9494
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
9595
// CHECK:STDERR: fail_import_integer_literal_too_big.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `CONFIG_VALUE` [InCppNameLookup]
@@ -264,7 +264,7 @@ import Cpp library "string_literal_object_like_macro.h";
264264

265265
fn F() {
266266
// TODO: Get rid of the second error.
267-
// CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+11]]:3: error: semantics TODO: `non-integer constant expression in macro.` [SemanticsTodo]
267+
// CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+11]]:3: error: semantics TODO: `Unsupported: macro evaluated to a constant of type: const char[4]` [SemanticsTodo]
268268
// CHECK:STDERR: Cpp.CONFIG_VALUE;
269269
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
270270
// CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `CONFIG_VALUE` [InCppNameLookup]
@@ -279,30 +279,75 @@ fn F() {
279279
}
280280

281281
// --- floating_point_literal_macro.h
282-
#define PI 3.14
282+
#define MyDouble 1.0
283+
#define MyDoubleE 1e2
284+
#define MyFloat 1.f
283285

284-
// --- fail_todo_floating_point_literal_macro.carbon
286+
// --- import_floating_point_literal_macro.carbon
285287

286288
library "[[@TEST_NAME]]";
287289

288290
import Cpp library "floating_point_literal_macro.h";
289291

290292
fn F() {
291-
// TODO: Get rid of the second error.
292-
// CHECK:STDERR: fail_todo_floating_point_literal_macro.carbon:[[@LINE+11]]:16: error: semantics TODO: `non-integer constant expression in macro.` [SemanticsTodo]
293-
// CHECK:STDERR: let a: f64 = Cpp.PI;
294-
// CHECK:STDERR: ^~~~~~
295-
// CHECK:STDERR: fail_todo_floating_point_literal_macro.carbon:[[@LINE+8]]:16: note: in `Cpp` name lookup for `PI` [InCppNameLookup]
296-
// CHECK:STDERR: let a: f64 = Cpp.PI;
297-
// CHECK:STDERR: ^~~~~~
293+
//@dump-sem-ir-begin
294+
let a: f64 = Cpp.MyDouble;
295+
let b: f64 = Cpp.MyDoubleE;
296+
let c: f32 = Cpp.MyFloat;
297+
//@dump-sem-ir-end
298+
}
299+
300+
// --- unsupported_floating_point_literal_macro.h
301+
#define MyLongDouble 987.654l
302+
303+
// --- fail_import_unsupported_floating_point_literal_macro.carbon
304+
305+
library "[[@TEST_NAME]]";
306+
307+
import Cpp library "unsupported_floating_point_literal_macro.h";
308+
309+
fn F() {
310+
// CHECK:STDERR: fail_import_unsupported_floating_point_literal_macro.carbon:[[@LINE+11]]:3: error: semantics TODO: `Unsupported: C++ literal's type `long double` could not be mapped to a Carbon type` [SemanticsTodo]
311+
// CHECK:STDERR: Cpp.MyLongDouble;
312+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
313+
// CHECK:STDERR: fail_import_unsupported_floating_point_literal_macro.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `MyLongDouble` [InCppNameLookup]
314+
// CHECK:STDERR: Cpp.MyLongDouble;
315+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
298316
// CHECK:STDERR:
299-
// CHECK:STDERR: fail_todo_floating_point_literal_macro.carbon:[[@LINE+4]]:16: error: member name `PI` not found in `Cpp` [MemberNameNotFoundInInstScope]
300-
// CHECK:STDERR: let a: f64 = Cpp.PI;
301-
// CHECK:STDERR: ^~~~~~
317+
// CHECK:STDERR: fail_import_unsupported_floating_point_literal_macro.carbon:[[@LINE+4]]:3: error: member name `MyLongDouble` not found in `Cpp` [MemberNameNotFoundInInstScope]
318+
// CHECK:STDERR: Cpp.MyLongDouble;
319+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
302320
// CHECK:STDERR:
303-
let a: f64 = Cpp.PI;
321+
Cpp.MyLongDouble;
304322
}
305323

324+
// --- fail_import_assign_to_float.carbon
325+
326+
library "[[@TEST_NAME]]";
327+
328+
import Cpp library "floating_point_literal_macro.h";
329+
330+
fn F() {
331+
// CHECK:STDERR: fail_import_assign_to_float.carbon:[[@LINE+4]]:3: error: expression is not assignable [AssignmentToNonAssignable]
332+
// CHECK:STDERR: Cpp.MyDouble = 1.0;
333+
// CHECK:STDERR: ^~~~~~~~~~~~
334+
// CHECK:STDERR:
335+
Cpp.MyDouble = 1.0;
336+
}
337+
338+
// --- lambda.carbon
339+
340+
library "[[@TEST_NAME]]";
341+
342+
import Cpp inline '''
343+
#define MyIntLambda (([] { return 7; })())
344+
''';
345+
346+
fn F() {
347+
let i: i32 = Cpp.MyIntLambda;
348+
}
349+
350+
306351
// --- macro_undefined.h
307352

308353
#define CONFIG_VALUE 1
@@ -722,6 +767,70 @@ fn F() {
722767
// CHECK:STDOUT: <elided>
723768
// CHECK:STDOUT: }
724769
// CHECK:STDOUT:
770+
// CHECK:STDOUT: --- import_floating_point_literal_macro.carbon
771+
// CHECK:STDOUT:
772+
// CHECK:STDOUT: constants {
773+
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete]
774+
// CHECK:STDOUT: %f64.d77: type = class_type @Float, @Float(%int_64) [concrete]
775+
// CHECK:STDOUT: %pattern_type.0ae: type = pattern_type %f64.d77 [concrete]
776+
// CHECK:STDOUT: %float.d20: %f64.d77 = float_value 1 [concrete]
777+
// CHECK:STDOUT: %float.e0c: %f64.d77 = float_value 100 [concrete]
778+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
779+
// CHECK:STDOUT: %f32.97e: type = class_type @Float, @Float(%int_32) [concrete]
780+
// CHECK:STDOUT: %pattern_type.201: type = pattern_type %f32.97e [concrete]
781+
// CHECK:STDOUT: %float.e3b: %f32.97e = float_value 1 [concrete]
782+
// CHECK:STDOUT: }
783+
// CHECK:STDOUT:
784+
// CHECK:STDOUT: imports {
785+
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
786+
// CHECK:STDOUT: .MyDouble = %float.d20
787+
// CHECK:STDOUT: .MyDoubleE = %float.e0c
788+
// CHECK:STDOUT: .MyFloat = %float.e3b
789+
// CHECK:STDOUT: import Cpp//...
790+
// CHECK:STDOUT: }
791+
// CHECK:STDOUT: %float.d20: %f64.d77 = float_value 1 [concrete = constants.%float.d20]
792+
// CHECK:STDOUT: %float.e0c: %f64.d77 = float_value 100 [concrete = constants.%float.e0c]
793+
// CHECK:STDOUT: %float.e3b: %f32.97e = float_value 1 [concrete = constants.%float.e3b]
794+
// CHECK:STDOUT: }
795+
// CHECK:STDOUT:
796+
// CHECK:STDOUT: fn @F() {
797+
// CHECK:STDOUT: !entry:
798+
// CHECK:STDOUT: name_binding_decl {
799+
// CHECK:STDOUT: %a.patt: %pattern_type.0ae = value_binding_pattern a [concrete]
800+
// CHECK:STDOUT: }
801+
// CHECK:STDOUT: %Cpp.ref.loc8: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
802+
// CHECK:STDOUT: <elided>
803+
// CHECK:STDOUT: %MyDouble.ref: %f64.d77 = name_ref MyDouble, imports.%float.d20 [concrete = constants.%float.d20]
804+
// CHECK:STDOUT: %.loc8: type = splice_block %f64.loc8 [concrete = constants.%f64.d77] {
805+
// CHECK:STDOUT: %int_64.loc8: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
806+
// CHECK:STDOUT: %f64.loc8: type = class_type @Float, @Float(constants.%int_64) [concrete = constants.%f64.d77]
807+
// CHECK:STDOUT: }
808+
// CHECK:STDOUT: %a: %f64.d77 = value_binding a, %MyDouble.ref
809+
// CHECK:STDOUT: name_binding_decl {
810+
// CHECK:STDOUT: %b.patt: %pattern_type.0ae = value_binding_pattern b [concrete]
811+
// CHECK:STDOUT: }
812+
// CHECK:STDOUT: %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
813+
// CHECK:STDOUT: <elided>
814+
// CHECK:STDOUT: %MyDoubleE.ref: %f64.d77 = name_ref MyDoubleE, imports.%float.e0c [concrete = constants.%float.e0c]
815+
// CHECK:STDOUT: %.loc9: type = splice_block %f64.loc9 [concrete = constants.%f64.d77] {
816+
// CHECK:STDOUT: %int_64.loc9: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
817+
// CHECK:STDOUT: %f64.loc9: type = class_type @Float, @Float(constants.%int_64) [concrete = constants.%f64.d77]
818+
// CHECK:STDOUT: }
819+
// CHECK:STDOUT: %b: %f64.d77 = value_binding b, %MyDoubleE.ref
820+
// CHECK:STDOUT: name_binding_decl {
821+
// CHECK:STDOUT: %c.patt: %pattern_type.201 = value_binding_pattern c [concrete]
822+
// CHECK:STDOUT: }
823+
// CHECK:STDOUT: %Cpp.ref.loc10: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
824+
// CHECK:STDOUT: <elided>
825+
// CHECK:STDOUT: %MyFloat.ref: %f32.97e = name_ref MyFloat, imports.%float.e3b [concrete = constants.%float.e3b]
826+
// CHECK:STDOUT: %.loc10: type = splice_block %f32.loc10 [concrete = constants.%f32.97e] {
827+
// CHECK:STDOUT: %int_32.loc10: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
828+
// CHECK:STDOUT: %f32.loc10: type = class_type @Float, @Float(constants.%int_32) [concrete = constants.%f32.97e]
829+
// CHECK:STDOUT: }
830+
// CHECK:STDOUT: %c: %f32.97e = value_binding c, %MyFloat.ref
831+
// CHECK:STDOUT: <elided>
832+
// CHECK:STDOUT: }
833+
// CHECK:STDOUT:
725834
// CHECK:STDOUT: --- import_macro_redefined.carbon
726835
// CHECK:STDOUT:
727836
// CHECK:STDOUT: constants {

toolchain/diagnostics/diagnostic_kind.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,6 @@ CARBON_DIAGNOSTIC_KIND(QualifiedDeclInIncompleteClassScope)
378378
CARBON_DIAGNOSTIC_KIND(QualifiedDeclInUndefinedInterfaceScope)
379379

380380
// Name lookup.
381-
CARBON_DIAGNOSTIC_KIND(InCppConstantMapping)
382381
CARBON_DIAGNOSTIC_KIND(InCppMacroEvaluation)
383382
CARBON_DIAGNOSTIC_KIND(InCppNameLookup)
384383
CARBON_DIAGNOSTIC_KIND(InNameLookup)

0 commit comments

Comments
 (0)