37
37
#include " toolchain/check/import.h"
38
38
#include " toolchain/check/inst.h"
39
39
#include " toolchain/check/literal.h"
40
+ #include " toolchain/check/operator.h"
40
41
#include " toolchain/check/pattern.h"
41
42
#include " toolchain/check/pattern_match.h"
42
43
#include " toolchain/check/type.h"
@@ -485,18 +486,27 @@ auto ImportCppFiles(Context& context,
485
486
return std::move (generated_ast);
486
487
}
487
488
488
- // Looks up the given name in the Clang AST in a specific scope. Returns the
489
- // lookup result if lookup was successful.
490
- static auto ClangLookupName (Context& context, SemIR::NameScopeId scope_id,
491
- SemIR::NameId name_id)
492
- -> std::optional<clang::LookupResult> {
493
- std::optional<llvm::StringRef> name =
494
- context.names ().GetAsStringIfIdentifier (name_id);
495
- if (!name) {
496
- // Special names never exist in C++ code.
497
- return std::nullopt ;
489
+ // Returns the Clang `DeclContext` for the given name scope. Return the
490
+ // translation unit decl if no scope is provided.
491
+ static auto GetDeclContext (Context& context, SemIR::NameScopeId scope_id)
492
+ -> clang::DeclContext* {
493
+ if (!scope_id.has_value ()) {
494
+ return context.ast_context ().getTranslationUnitDecl ();
498
495
}
496
+ auto scope_clang_decl_context_id =
497
+ context.name_scopes ().Get (scope_id).clang_decl_context_id ();
498
+ return dyn_cast<clang::DeclContext>(
499
+ context.sem_ir ().clang_decls ().Get (scope_clang_decl_context_id).decl );
500
+ }
499
501
502
+ // Looks up the given declaration name in the Clang AST in a specific scope.
503
+ // Returns the found declaration and its access. If not found, returns
504
+ // `nullopt`. If there's not a single result, returns `nullptr` and default
505
+ // access.
506
+ static auto ClangLookupDeclarationName (Context& context, SemIR::LocId loc_id,
507
+ SemIR::NameScopeId scope_id,
508
+ clang::DeclarationName name)
509
+ -> std::optional<std::tuple<clang::NamedDecl*, clang::AccessSpecifier>> {
500
510
clang::ASTUnit* ast = context.sem_ir ().clang_ast_unit ();
501
511
CARBON_CHECK (ast);
502
512
clang::Sema& sema = ast->getSema ();
@@ -505,26 +515,36 @@ static auto ClangLookupName(Context& context, SemIR::NameScopeId scope_id,
505
515
// here so that clang's diagnostics can point into the carbon code that uses
506
516
// the name.
507
517
clang::LookupResult lookup (
508
- sema,
509
- clang::DeclarationNameInfo (
510
- clang::DeclarationName (
511
- sema.getPreprocessor ().getIdentifierInfo (*name)),
512
- clang::SourceLocation ()),
518
+ sema, clang::DeclarationNameInfo (name, clang::SourceLocation ()),
513
519
clang::Sema::LookupNameKind::LookupOrdinaryName);
514
520
515
- auto scope_clang_decl_context_id =
516
- context.name_scopes ().Get (scope_id).clang_decl_context_id ();
517
- bool found = sema.LookupQualifiedName (
518
- lookup, dyn_cast<clang::DeclContext>(context.sem_ir ()
519
- .clang_decls ()
520
- .Get (scope_clang_decl_context_id)
521
- .decl ));
521
+ bool found =
522
+ sema.LookupQualifiedName (lookup, GetDeclContext (context, scope_id));
522
523
523
524
if (!found) {
524
525
return std::nullopt ;
525
526
}
526
527
527
- return lookup;
528
+ std::tuple<clang::NamedDecl*, clang::AccessSpecifier> result{
529
+ nullptr , clang::AccessSpecifier::AS_none};
530
+
531
+ // Access checks are performed separately by the Carbon name lookup logic.
532
+ lookup.suppressAccessDiagnostics ();
533
+
534
+ if (!lookup.isSingleResult ()) {
535
+ // Clang will diagnose ambiguous lookup results for us.
536
+ if (!lookup.isAmbiguous ()) {
537
+ context.TODO (loc_id,
538
+ llvm::formatv (" Unsupported: Lookup succeeded but couldn't "
539
+ " find a single result; LookupResultKind: {0}" ,
540
+ static_cast <int >(lookup.getResultKind ())));
541
+ }
542
+
543
+ return result;
544
+ }
545
+
546
+ result = {lookup.getFoundDecl (), lookup.begin ().getAccess ()};
547
+ return result;
528
548
}
529
549
530
550
// Looks up for constructors in the class scope and returns the lookup result.
@@ -573,43 +593,48 @@ static auto IsDeclInjectedClassName(const Context& context,
573
593
return true ;
574
594
}
575
595
596
+ // Returns a Clang DeclarationName for the given `NameId`.
597
+ static auto GetDeclarationName (Context& context, SemIR::NameId name_id)
598
+ -> std::optional<clang::DeclarationName> {
599
+ std::optional<llvm::StringRef> name =
600
+ context.names ().GetAsStringIfIdentifier (name_id);
601
+ if (!name) {
602
+ // Special names never exist in C++ code.
603
+ return std::nullopt ;
604
+ }
605
+
606
+ return clang::DeclarationName (context.sem_ir ()
607
+ .clang_ast_unit ()
608
+ ->getSema ()
609
+ .getPreprocessor ()
610
+ .getIdentifierInfo (*name));
611
+ }
612
+
576
613
// Looks up the given name in the Clang AST in a specific scope, and returns the
577
614
// found declaration and its access. If the found declaration is the injected
578
615
// class name, looks up constructors instead. If not found, returns `nullopt`.
579
616
// If there's not a single result, returns `nullptr` and default access.
580
617
// Otherwise, returns the single declaration and its access.
581
- static auto ClangLookup (Context& context, SemIR::LocId loc_id,
582
- SemIR::NameScopeId scope_id, SemIR::NameId name_id)
618
+ static auto ClangLookupName (Context& context, SemIR::LocId loc_id,
619
+ SemIR::NameScopeId scope_id, SemIR::NameId name_id)
583
620
-> std::optional<std::tuple<clang::NamedDecl*, clang::AccessSpecifier>> {
584
- auto lookup = ClangLookupName (context, scope_id , name_id);
585
- if (!lookup ) {
621
+ auto declaration_name = GetDeclarationName (context, name_id);
622
+ if (!declaration_name ) {
586
623
return std::nullopt ;
587
624
}
588
-
589
- std::tuple<clang::NamedDecl*, clang::AccessSpecifier> result{
590
- nullptr , clang::AccessSpecifier::AS_none};
591
-
592
- // Access checks are performed separately by the Carbon name lookup logic.
593
- lookup->suppressAccessDiagnostics ();
594
-
595
- if (!lookup->isSingleResult ()) {
596
- // Clang will diagnose ambiguous lookup results for us.
597
- if (!lookup->isAmbiguous ()) {
598
- context.TODO (loc_id,
599
- llvm::formatv (" Unsupported: Lookup succeeded but couldn't "
600
- " find a single result; LookupResultKind: {0}" ,
601
- static_cast <int >(lookup->getResultKind ())));
602
- }
603
-
625
+ auto result =
626
+ ClangLookupDeclarationName (context, loc_id, scope_id, *declaration_name);
627
+ if (!result) {
604
628
return result;
605
629
}
606
630
607
- if (!IsDeclInjectedClassName (context, scope_id, name_id,
608
- lookup->getFoundDecl ())) {
609
- result = {lookup->getFoundDecl (), lookup->begin ().getAccess ()};
631
+ clang::NamedDecl* decl = std::get<0 >(*result);
632
+ if (!decl || !IsDeclInjectedClassName (context, scope_id, name_id, decl)) {
610
633
return result;
611
634
}
612
635
636
+ result = {nullptr , clang::AccessSpecifier::AS_none};
637
+
613
638
clang::DeclContextLookupResult constructors_lookup =
614
639
ClangConstructorLookup (context, scope_id);
615
640
@@ -1606,6 +1631,29 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id,
1606
1631
.call_params_id = call_params_id}};
1607
1632
}
1608
1633
1634
+ // Returns the Carbon function name for the given function.
1635
+ static auto GetFunctionName (Context& context, clang::FunctionDecl* clang_decl)
1636
+ -> SemIR::NameId {
1637
+ switch (clang_decl->getDeclName ().getNameKind ()) {
1638
+ case clang::DeclarationName::CXXConstructorName: {
1639
+ return context.classes ()
1640
+ .Get (context.insts ()
1641
+ .GetAs <SemIR::ClassDecl>(LookupClangDeclInstId (
1642
+ context, cast<clang::Decl>(clang_decl->getParent ())))
1643
+ .class_id )
1644
+ .name_id ;
1645
+ }
1646
+
1647
+ case clang::DeclarationName::CXXOperatorName: {
1648
+ return SemIR::NameId::CppOperator;
1649
+ }
1650
+
1651
+ default : {
1652
+ return AddIdentifierName (context, clang_decl->getName ());
1653
+ }
1654
+ }
1655
+ }
1656
+
1609
1657
// Creates a `FunctionDecl` and a `Function` without C++ thunk information.
1610
1658
// Returns std::nullopt on failure. The given Clang declaration is assumed to:
1611
1659
// * Have not been imported before.
@@ -1634,19 +1682,8 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id,
1634
1682
AddPlaceholderInstInNoBlock (context, Parse::NodeId::None, function_decl);
1635
1683
context.imports ().push_back (decl_id);
1636
1684
1637
- SemIR::NameId function_name_id =
1638
- isa<clang::CXXConstructorDecl>(clang_decl)
1639
- ? context.classes ()
1640
- .Get (context.insts ()
1641
- .GetAs <SemIR::ClassDecl>(LookupClangDeclInstId (
1642
- context,
1643
- cast<clang::Decl>(clang_decl->getParent ())))
1644
- .class_id )
1645
- .name_id
1646
- : AddIdentifierName (context, clang_decl->getName ());
1647
-
1648
1685
auto function_info = SemIR::Function{
1649
- {.name_id = function_name_id ,
1686
+ {.name_id = GetFunctionName (context, clang_decl) ,
1650
1687
.parent_scope_id = GetParentNameScopeId (context, clang_decl),
1651
1688
.generic_id = SemIR::GenericId::None,
1652
1689
.first_param_node_id = Parse::NodeId::None,
@@ -1965,7 +2002,7 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
1965
2002
builder.Note (loc_id, InCppNameLookup, name_id);
1966
2003
});
1967
2004
1968
- auto decl_and_access = ClangLookup (context, loc_id, scope_id, name_id);
2005
+ auto decl_and_access = ClangLookupName (context, loc_id, scope_id, name_id);
1969
2006
if (!decl_and_access) {
1970
2007
return SemIR::ScopeLookupResult::MakeNotFound ();
1971
2008
}
@@ -1980,4 +2017,56 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
1980
2017
access);
1981
2018
}
1982
2019
2020
+ static auto GetOperatorKind (Context& context, SemIR::LocId loc_id,
2021
+ llvm::StringLiteral interface_name)
2022
+ -> std::optional<clang::OverloadedOperatorKind> {
2023
+ if (interface_name == " AddWith" ) {
2024
+ return clang::OO_Plus;
2025
+ }
2026
+
2027
+ context.TODO (loc_id, llvm::formatv (" Unsupported operator interface `{0}`" ,
2028
+ interface_name));
2029
+ return std::nullopt ;
2030
+ }
2031
+
2032
+ auto ImportOperatorFromCpp (Context& context, SemIR::LocId loc_id, Operator op)
2033
+ -> SemIR::ScopeLookupResult {
2034
+ Diagnostics::AnnotationScope annotate_diagnostics (
2035
+ &context.emitter (), [&](auto & builder) {
2036
+ CARBON_DIAGNOSTIC (InCppOperatorLookup, Note,
2037
+ " in `Cpp` operator `{0}` lookup" , std::string);
2038
+ builder.Note (loc_id, InCppOperatorLookup, op.interface_name .str ());
2039
+ });
2040
+
2041
+ auto op_kind = GetOperatorKind (context, loc_id, op.interface_name );
2042
+ if (!op_kind) {
2043
+ return SemIR::ScopeLookupResult::MakeNotFound ();
2044
+ }
2045
+
2046
+ // TODO: We should do ADL-only lookup for operators
2047
+ // (`Sema::ArgumentDependentLookup`), when we support mapping Carbon types
2048
+ // into C++ types. See
2049
+ // https://github.com/carbon-language/carbon-lang/pull/5996/files/5d01fa69511b76f87efbc0387f5e40abcf4c911a#r2316950123
2050
+ auto decl_and_access = ClangLookupDeclarationName (
2051
+ context, loc_id, SemIR::NameScopeId::None,
2052
+ context.ast_context ().DeclarationNames .getCXXOperatorName (*op_kind));
2053
+
2054
+ if (!decl_and_access) {
2055
+ return SemIR::ScopeLookupResult::MakeNotFound ();
2056
+ }
2057
+ auto [decl, access] = *decl_and_access;
2058
+ if (!decl) {
2059
+ return SemIR::ScopeLookupResult::MakeError ();
2060
+ }
2061
+
2062
+ SemIR::InstId inst_id = ImportDeclAndDependencies (context, loc_id, decl);
2063
+ if (!inst_id.has_value ()) {
2064
+ return SemIR::ScopeLookupResult::MakeNotFound ();
2065
+ }
2066
+
2067
+ SemIR::AccessKind access_kind = MapAccess (access);
2068
+ return SemIR::ScopeLookupResult::MakeWrappedLookupResult (inst_id,
2069
+ access_kind);
2070
+ }
2071
+
1983
2072
} // namespace Carbon::Check
0 commit comments