45
45
#include " toolchain/diagnostics/format_providers.h"
46
46
#include " toolchain/parse/node_ids.h"
47
47
#include " toolchain/sem_ir/clang_decl.h"
48
+ #include " toolchain/sem_ir/class.h"
48
49
#include " toolchain/sem_ir/function.h"
49
50
#include " toolchain/sem_ir/ids.h"
50
51
#include " toolchain/sem_ir/inst.h"
@@ -455,10 +456,10 @@ auto ImportCppFiles(Context& context,
455
456
return std::move (generated_ast);
456
457
}
457
458
458
- // Look ups the given name in the Clang AST in a specific scope. Returns the
459
+ // Looks up the given name in the Clang AST in a specific scope. Returns the
459
460
// lookup result if lookup was successful.
460
- static auto ClangLookup (Context& context, SemIR::NameScopeId scope_id,
461
- SemIR::NameId name_id)
461
+ static auto ClangLookupName (Context& context, SemIR::NameScopeId scope_id,
462
+ SemIR::NameId name_id)
462
463
-> std::optional<clang::LookupResult> {
463
464
std::optional<llvm::StringRef> name =
464
465
context.names ().GetAsStringIfIdentifier (name_id);
@@ -497,6 +498,112 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id,
497
498
return lookup;
498
499
}
499
500
501
+ // Looks up for constructors in the class scope and returns the lookup result.
502
+ static auto ClangConstructorLookup (const Context& context,
503
+ SemIR::NameScopeId scope_id)
504
+ -> clang::DeclContextLookupResult {
505
+ const SemIR::NameScope& scope = context.sem_ir ().name_scopes ().Get (scope_id);
506
+
507
+ clang::Sema& sema = context.sem_ir ().cpp_ast ()->getSema ();
508
+ clang::Decl* decl =
509
+ context.sem_ir ().clang_decls ().Get (scope.clang_decl_context_id ()).decl ;
510
+ return sema.LookupConstructors (cast<clang::CXXRecordDecl>(decl));
511
+ }
512
+
513
+ // Returns true if the given Clang declaration is the implicit injected class
514
+ // name within the class.
515
+ static auto IsDeclInjectedClassName (const Context& context,
516
+ SemIR::NameScopeId scope_id,
517
+ SemIR::NameId name_id,
518
+ const clang::NamedDecl* named_decl)
519
+ -> bool {
520
+ if (!named_decl->isImplicit ()) {
521
+ return false ;
522
+ }
523
+
524
+ const auto * record_decl = dyn_cast<clang::CXXRecordDecl>(named_decl);
525
+ if (!record_decl) {
526
+ return false ;
527
+ }
528
+
529
+ const SemIR::ClangDecl& clang_decl = context.sem_ir ().clang_decls ().Get (
530
+ context.sem_ir ().name_scopes ().Get (scope_id).clang_decl_context_id ());
531
+ const auto * scope_record_decl = cast<clang::CXXRecordDecl>(clang_decl.decl );
532
+
533
+ const clang::ASTContext& ast_context =
534
+ context.sem_ir ().cpp_ast ()->getASTContext ();
535
+ CARBON_CHECK (
536
+ ast_context.getCanonicalType (
537
+ ast_context.getRecordType (scope_record_decl)) ==
538
+ ast_context.getCanonicalType (ast_context.getRecordType (record_decl)));
539
+
540
+ auto class_decl =
541
+ context.sem_ir ().insts ().GetAs <SemIR::ClassDecl>(clang_decl.inst_id );
542
+ CARBON_CHECK (name_id ==
543
+ context.sem_ir ().classes ().Get (class_decl.class_id ).name_id );
544
+ return true ;
545
+ }
546
+
547
+ // Looks up the given name in the Clang AST in a specific scope, and returns the
548
+ // found declaration and its access. If the found declaration is the injected
549
+ // class name, looks up constructors instead. If not found, returns `nullopt`.
550
+ // If there's not a single result, returns `nullptr` and default access.
551
+ // Otherwise, returns the single declaration and its access.
552
+ static auto ClangLookup (Context& context, SemIR::LocId loc_id,
553
+ SemIR::NameScopeId scope_id, SemIR::NameId name_id)
554
+ -> std::optional<std::tuple<clang::NamedDecl*, clang::AccessSpecifier>> {
555
+ auto lookup = ClangLookupName (context, scope_id, name_id);
556
+ if (!lookup) {
557
+ return std::nullopt;
558
+ }
559
+
560
+ std::tuple<clang::NamedDecl*, clang::AccessSpecifier> result{
561
+ nullptr , clang::AccessSpecifier::AS_none};
562
+
563
+ // Access checks are performed separately by the Carbon name lookup logic.
564
+ lookup->suppressAccessDiagnostics ();
565
+
566
+ if (!lookup->isSingleResult ()) {
567
+ // Clang will diagnose ambiguous lookup results for us.
568
+ if (!lookup->isAmbiguous ()) {
569
+ context.TODO (loc_id,
570
+ llvm::formatv (" Unsupported: Lookup succeeded but couldn't "
571
+ " find a single result; LookupResultKind: {0}" ,
572
+ static_cast <int >(lookup->getResultKind ())));
573
+ }
574
+
575
+ return result;
576
+ }
577
+
578
+ if (!IsDeclInjectedClassName (context, scope_id, name_id,
579
+ lookup->getFoundDecl ())) {
580
+ result = {lookup->getFoundDecl (), lookup->begin ().getAccess ()};
581
+ return result;
582
+ }
583
+
584
+ clang::DeclContextLookupResult constructors_lookup =
585
+ ClangConstructorLookup (context, scope_id);
586
+
587
+ llvm::SmallVector<clang::CXXConstructorDecl*> constructors;
588
+ for (clang::Decl* decl : constructors_lookup) {
589
+ auto * constructor = cast<clang::CXXConstructorDecl>(decl);
590
+ if (constructor->isDeleted () || constructor->isCopyOrMoveConstructor ()) {
591
+ continue ;
592
+ }
593
+ constructors.push_back (constructor);
594
+ }
595
+ if (constructors.size () != 1 ) {
596
+ context.TODO (
597
+ loc_id,
598
+ llvm::formatv (" Unsupported: Constructors lookup succeeded but couldn't "
599
+ " find a single result; Found {0} constructors" ,
600
+ constructors.size ()));
601
+ return result;
602
+ }
603
+ result = {constructors[0 ], constructors[0 ]->getAccess ()};
604
+ return result;
605
+ }
606
+
500
607
// Returns whether `decl` already mapped to an instruction.
501
608
static auto IsClangDeclImported (const Context& context, clang::Decl* decl)
502
609
-> bool {
@@ -1109,7 +1216,8 @@ static auto MakeImplicitParamPatternsBlockId(
1109
1216
Context& context, SemIR::LocId loc_id,
1110
1217
const clang::FunctionDecl& clang_decl) -> SemIR::InstBlockId {
1111
1218
const auto * method_decl = dyn_cast<clang::CXXMethodDecl>(&clang_decl);
1112
- if (!method_decl || method_decl->isStatic ()) {
1219
+ if (!method_decl || method_decl->isStatic () ||
1220
+ isa<clang::CXXConstructorDecl>(clang_decl)) {
1113
1221
return SemIR::InstBlockId::Empty;
1114
1222
}
1115
1223
@@ -1229,22 +1337,54 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
1229
1337
return context.inst_blocks ().Add (params);
1230
1338
}
1231
1339
1232
- // Returns the return type of the given function declaration. In case of an
1233
- // unsupported return type, it produces a diagnostic and returns
1234
- // `SemIR::ErrorInst::InstId` .
1340
+ // Returns the return `TypeExpr` of the given function declaration. In case of
1341
+ // an unsupported return type, returns `SemIR::ErrorInst::InstId`. Constructors
1342
+ // are treated as returning a class instance .
1235
1343
// TODO: Support more return types.
1236
- static auto GetReturnType (Context& context, SemIR::LocId loc_id,
1237
- const clang::FunctionDecl* clang_decl)
1238
- -> SemIR::InstId {
1344
+ static auto GetReturnTypeExpr (Context& context, SemIR::LocId loc_id,
1345
+ clang::FunctionDecl* clang_decl) -> TypeExpr {
1239
1346
clang::QualType ret_type = clang_decl->getReturnType ();
1240
- if (ret_type->isVoidType ()) {
1241
- return SemIR::InstId::None;
1347
+ if (!ret_type->isVoidType ()) {
1348
+ TypeExpr mapped_type = MapType (context, loc_id, ret_type);
1349
+ if (!mapped_type.inst_id .has_value ()) {
1350
+ return {.inst_id = SemIR::ErrorInst::TypeInstId,
1351
+ .type_id = SemIR::ErrorInst::TypeId};
1352
+ }
1353
+ return mapped_type;
1354
+ }
1355
+
1356
+ if (!isa<clang::CXXConstructorDecl>(clang_decl)) {
1357
+ // void.
1358
+ return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
1242
1359
}
1243
1360
1244
- auto [type_inst_id, type_id] = MapType (context, loc_id, ret_type);
1361
+ // TODO: Make this a `PartialType`.
1362
+ SemIR::TypeInstId record_type_inst_id = context.types ().GetAsTypeInstId (
1363
+ context.sem_ir ()
1364
+ .clang_decls ()
1365
+ .Get (context.sem_ir ().clang_decls ().Lookup (
1366
+ cast<clang::Decl>(clang_decl->getParent ())))
1367
+ .inst_id );
1368
+ return {
1369
+ .inst_id = record_type_inst_id,
1370
+ .type_id = context.types ().GetTypeIdForTypeInstId (record_type_inst_id)};
1371
+ }
1372
+
1373
+ // Returns the return pattern of the given function declaration. In case of an
1374
+ // unsupported return type, it produces a diagnostic and returns
1375
+ // `SemIR::ErrorInst::InstId`. Constructors are treated as returning a class
1376
+ // instance.
1377
+ static auto GetReturnPattern (Context& context, SemIR::LocId loc_id,
1378
+ clang::FunctionDecl* clang_decl) -> SemIR::InstId {
1379
+ auto [type_inst_id, type_id] = GetReturnTypeExpr (context, loc_id, clang_decl);
1245
1380
if (!type_inst_id.has_value ()) {
1246
- context.TODO (loc_id, llvm::formatv (" Unsupported: return type: {0}" ,
1247
- ret_type.getAsString ()));
1381
+ // void.
1382
+ return SemIR::InstId::None;
1383
+ }
1384
+ if (type_inst_id == SemIR::ErrorInst::TypeInstId) {
1385
+ context.TODO (loc_id,
1386
+ llvm::formatv (" Unsupported: return type: {0}" ,
1387
+ clang_decl->getReturnType ().getAsString ()));
1248
1388
return SemIR::ErrorInst::InstId;
1249
1389
}
1250
1390
auto pattern_type_id = GetPatternType (context, type_id);
@@ -1283,10 +1423,10 @@ struct FunctionParamsInsts {
1283
1423
// Produces a diagnostic and returns `std::nullopt` if the function declaration
1284
1424
// has an unsupported parameter type.
1285
1425
static auto CreateFunctionParamsInsts (Context& context, SemIR::LocId loc_id,
1286
- const clang::FunctionDecl* clang_decl)
1426
+ clang::FunctionDecl* clang_decl)
1287
1427
-> std::optional<FunctionParamsInsts> {
1288
- if (isa<clang::CXXConstructorDecl, clang:: CXXDestructorDecl>(clang_decl)) {
1289
- context.TODO (loc_id, " Unsupported: Constructor/ Destructor" );
1428
+ if (isa<clang::CXXDestructorDecl>(clang_decl)) {
1429
+ context.TODO (loc_id, " Unsupported: Destructor" );
1290
1430
return std::nullopt;
1291
1431
}
1292
1432
@@ -1300,7 +1440,7 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id,
1300
1440
if (!param_patterns_id.has_value ()) {
1301
1441
return std::nullopt;
1302
1442
}
1303
- auto return_slot_pattern_id = GetReturnType (context, loc_id, clang_decl);
1443
+ auto return_slot_pattern_id = GetReturnPattern (context, loc_id, clang_decl);
1304
1444
if (SemIR::ErrorInst::InstId == return_slot_pattern_id) {
1305
1445
return std::nullopt;
1306
1446
}
@@ -1343,8 +1483,19 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id,
1343
1483
AddPlaceholderInstInNoBlock (context, Parse::NodeId::None, function_decl);
1344
1484
context.imports ().push_back (decl_id);
1345
1485
1486
+ SemIR::NameId function_name_id =
1487
+ isa<clang::CXXConstructorDecl>(clang_decl)
1488
+ ? context.classes ()
1489
+ .Get (context.insts ()
1490
+ .GetAs <SemIR::ClassDecl>(LookupClangDeclInstId (
1491
+ context,
1492
+ cast<clang::Decl>(clang_decl->getParent ())))
1493
+ .class_id )
1494
+ .name_id
1495
+ : AddIdentifierName (context, clang_decl->getName ());
1496
+
1346
1497
auto function_info = SemIR::Function{
1347
- {.name_id = AddIdentifierName (context, clang_decl-> getName ()) ,
1498
+ {.name_id = function_name_id ,
1348
1499
.parent_scope_id = GetParentNameScopeId (context, clang_decl),
1349
1500
.generic_id = SemIR::GenericId::None,
1350
1501
.first_param_node_id = Parse::NodeId::None,
@@ -1526,8 +1677,7 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id,
1526
1677
}
1527
1678
1528
1679
context.TODO (loc_id, llvm::formatv (" Unsupported: Declaration type {0}" ,
1529
- clang_decl->getDeclKindName ())
1530
- .str ());
1680
+ clang_decl->getDeclKindName ()));
1531
1681
return SemIR::InstId::None;
1532
1682
}
1533
1683
@@ -1600,31 +1750,19 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
1600
1750
builder.Note (loc_id, InCppNameLookup, name_id);
1601
1751
});
1602
1752
1603
- auto lookup = ClangLookup (context, scope_id, name_id);
1604
- if (!lookup ) {
1753
+ auto decl_and_access = ClangLookup (context, loc_id , scope_id, name_id);
1754
+ if (!decl_and_access ) {
1605
1755
return SemIR::ScopeLookupResult::MakeNotFound ();
1606
1756
}
1607
-
1608
- // Access checks are performed separately by the Carbon name lookup logic.
1609
- lookup->suppressAccessDiagnostics ();
1610
-
1611
- if (!lookup->isSingleResult ()) {
1612
- // Clang will diagnose ambiguous lookup results for us.
1613
- if (!lookup->isAmbiguous ()) {
1614
- context.TODO (loc_id,
1615
- llvm::formatv (" Unsupported: Lookup succeeded but couldn't "
1616
- " find a single result; LookupResultKind: {0}" ,
1617
- static_cast <int >(lookup->getResultKind ()))
1618
- .str ());
1619
- }
1757
+ auto [decl, access] = *decl_and_access;
1758
+ if (!decl) {
1620
1759
context.name_scopes ().AddRequiredName (scope_id, name_id,
1621
1760
SemIR::ErrorInst::InstId);
1622
1761
return SemIR::ScopeLookupResult::MakeError ();
1623
1762
}
1624
1763
1625
- return ImportNameDeclIntoScope (context, loc_id, scope_id, name_id,
1626
- lookup->getFoundDecl (),
1627
- lookup->begin ().getAccess ());
1764
+ return ImportNameDeclIntoScope (context, loc_id, scope_id, name_id, decl,
1765
+ access);
1628
1766
}
1629
1767
1630
1768
} // namespace Carbon::Check
0 commit comments