@@ -680,8 +680,8 @@ static auto ImportNamespaceDecl(Context& context,
680
680
return result.inst_id ;
681
681
}
682
682
683
- static auto MapType (Context& context, SemIR::LocId loc_id, clang::QualType type)
684
- -> TypeExpr;
683
+ static auto ImportTypeAndDependencies (Context& context, SemIR::LocId loc_id,
684
+ clang::QualType type) -> TypeExpr;
685
685
686
686
// Creates a class declaration for the given class name in the given scope.
687
687
// Returns the `InstId` for the declaration.
@@ -828,7 +828,7 @@ static auto ImportClassObjectRepr(Context& context, SemIR::ClassId class_id,
828
828
" Should not import definition for class with a virtual base" );
829
829
830
830
auto [base_type_inst_id, base_type_id] =
831
- MapType (context, import_ir_inst_id, base.getType ());
831
+ ImportTypeAndDependencies (context, import_ir_inst_id, base.getType ());
832
832
if (!base_type_id.has_value ()) {
833
833
// TODO: If the base class's type can't be mapped, skip it.
834
834
continue ;
@@ -898,7 +898,7 @@ static auto ImportClassObjectRepr(Context& context, SemIR::ClassId class_id,
898
898
899
899
auto field_name_id = AddIdentifierName (context, field->getName ());
900
900
auto [field_type_inst_id, field_type_id] =
901
- MapType (context, import_ir_inst_id, field->getType ());
901
+ ImportTypeAndDependencies (context, import_ir_inst_id, field->getType ());
902
902
if (!field_type_inst_id.has_value ()) {
903
903
// TODO: For now, just skip over fields whose types we can't map.
904
904
continue ;
@@ -1577,22 +1577,33 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
1577
1577
return function_info.first_owning_decl_id ;
1578
1578
}
1579
1579
1580
- using DeclSet = llvm::SetVector<clang::Decl*>;
1580
+ namespace {
1581
+ // An item to be imported in an import worklist.
1582
+ // TODO: If worklists ever become particularly large, consider changing this
1583
+ // to use a `PointerIntPair`.
1584
+ struct ImportItem {
1585
+ // A declaration that we want to import.
1586
+ clang::Decl* decl;
1587
+ // Whether we have added `decl`'s dependencies to the worklist.
1588
+ bool added_dependencies;
1589
+ };
1590
+ // A worklist of declarations to import.
1591
+ using ImportWorklist = llvm::SmallVector<ImportItem>;
1592
+ } // namespace
1581
1593
1582
1594
// Adds the given declaration to our list of declarations to import.
1583
1595
static auto AddDependentDecl (const Context& context, clang::Decl* decl,
1584
- DeclSet& decls) -> void {
1585
- // TODO: Do we need to also add the parent of the declaration, recursively?
1596
+ ImportWorklist& worklist) -> void {
1586
1597
if (!IsClangDeclImported (context, decl)) {
1587
- decls. insert ( decl);
1598
+ worklist. push_back ({. decl = decl, . added_dependencies = false } );
1588
1599
}
1589
1600
}
1590
1601
1591
1602
// Finds all decls that need to be imported before importing the given type and
1592
1603
// adds them to the given set.
1593
1604
static auto AddDependentUnimportedTypeDecls (const Context& context,
1594
1605
clang::QualType type,
1595
- DeclSet& decls ) -> void {
1606
+ ImportWorklist& worklist ) -> void {
1596
1607
while (true ) {
1597
1608
if (type->isPointerType () || type->isReferenceType ()) {
1598
1609
type = type->getPointeeType ();
@@ -1605,41 +1616,45 @@ static auto AddDependentUnimportedTypeDecls(const Context& context,
1605
1616
}
1606
1617
1607
1618
if (const auto * record_type = type->getAs <clang::RecordType>()) {
1608
- AddDependentDecl (context, record_type->getDecl (), decls );
1619
+ AddDependentDecl (context, record_type->getDecl (), worklist );
1609
1620
}
1610
1621
}
1611
1622
1612
1623
// Finds all decls that need to be imported before importing the given function
1613
1624
// and adds them to the given set.
1614
1625
static auto AddDependentUnimportedFunctionDecls (
1615
1626
const Context& context, const clang::FunctionDecl& clang_decl,
1616
- DeclSet& decls ) -> void {
1627
+ ImportWorklist& worklist ) -> void {
1617
1628
for (const auto * param : clang_decl.parameters ()) {
1618
- AddDependentUnimportedTypeDecls (context, param->getType (), decls );
1629
+ AddDependentUnimportedTypeDecls (context, param->getType (), worklist );
1619
1630
}
1620
- AddDependentUnimportedTypeDecls (context, clang_decl.getReturnType (), decls);
1631
+ AddDependentUnimportedTypeDecls (context, clang_decl.getReturnType (),
1632
+ worklist);
1621
1633
}
1622
1634
1623
1635
// Finds all decls that need to be imported before importing the given
1624
1636
// declaration and adds them to the given set.
1625
1637
static auto AddDependentUnimportedDecls (const Context& context,
1626
- clang::Decl* clang_decl, DeclSet& decls)
1627
- -> void {
1628
- if (auto * parent_decl = GetParentDecl (clang_decl)) {
1629
- AddDependentDecl (context, parent_decl, decls);
1630
- }
1631
-
1638
+ clang::Decl* clang_decl,
1639
+ ImportWorklist& worklist) -> void {
1632
1640
if (auto * clang_function_decl = clang_decl->getAsFunction ()) {
1633
- AddDependentUnimportedFunctionDecls (context, *clang_function_decl, decls);
1641
+ AddDependentUnimportedFunctionDecls (context, *clang_function_decl,
1642
+ worklist);
1634
1643
} else if (auto * type_decl = dyn_cast<clang::TypeDecl>(clang_decl)) {
1635
- AddDependentUnimportedTypeDecls (
1636
- context, type_decl->getASTContext ().getTypeDeclType (type_decl), decls);
1644
+ if (!isa<clang::RecordDecl>(clang_decl)) {
1645
+ AddDependentUnimportedTypeDecls (
1646
+ context, type_decl->getASTContext ().getTypeDeclType (type_decl),
1647
+ worklist);
1648
+ }
1649
+ }
1650
+ if (!isa<clang::TranslationUnitDecl>(clang_decl)) {
1651
+ AddDependentDecl (context, GetParentDecl (clang_decl), worklist);
1637
1652
}
1638
1653
}
1639
1654
1640
- // Imports a declaration from Clang to Carbon. If successful, returns the
1641
- // instruction for the new Carbon declaration. Assumes all dependencies have
1642
- // already been imported.
1655
+ // Imports a declaration from Clang to Carbon. Returns the instruction for the
1656
+ // new Carbon declaration, which will be an ErrorInst on failure . Assumes all
1657
+ // dependencies have already been imported.
1643
1658
static auto ImportDeclAfterDependencies (Context& context, SemIR::LocId loc_id,
1644
1659
clang::Decl* clang_decl)
1645
1660
-> SemIR::InstId {
@@ -1658,6 +1673,8 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id,
1658
1673
type.getAsString ()));
1659
1674
return SemIR::ErrorInst::InstId;
1660
1675
}
1676
+ context.sem_ir ().clang_decls ().Add (
1677
+ {.decl = clang_decl, .inst_id = type_inst_id});
1661
1678
return type_inst_id;
1662
1679
}
1663
1680
if (isa<clang::FieldDecl, clang::IndirectFieldDecl>(clang_decl)) {
@@ -1678,30 +1695,71 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id,
1678
1695
return SemIR::ErrorInst::InstId;
1679
1696
}
1680
1697
1698
+ // Attempts to import a set of declarations. Returns `false` if an error was
1699
+ // produced, `true` otherwise.
1700
+ static auto ImportDeclSet (Context& context, SemIR::LocId loc_id,
1701
+ ImportWorklist& worklist) -> bool {
1702
+ // Walk the dependency graph in depth-first order, and import declarations
1703
+ // once we've imported all of their dependencies.
1704
+ while (!worklist.empty ()) {
1705
+ auto & item = worklist.back ();
1706
+ if (!item.added_dependencies ) {
1707
+ // Skip items we've already imported. We checked this when initially
1708
+ // adding the item to the worklist, but it might have been added to the
1709
+ // worklist twice before the first time we visited it. For example, this
1710
+ // happens for `fn F(a: Cpp.T, b: Cpp.T)`.
1711
+ if (IsClangDeclImported (context, item.decl )) {
1712
+ worklist.pop_back ();
1713
+ continue ;
1714
+ }
1715
+
1716
+ // First time visiting this declaration (preorder): add its dependencies
1717
+ // to the work list.
1718
+ item.added_dependencies = true ;
1719
+ AddDependentUnimportedDecls (context, item.decl , worklist);
1720
+ } else {
1721
+ // Second time visiting this declaration (postorder): its dependencies are
1722
+ // already imported, so we can import it now.
1723
+ auto * decl = worklist.pop_back_val ().decl ;
1724
+ auto inst_id = ImportDeclAfterDependencies (context, loc_id, decl);
1725
+ CARBON_CHECK (inst_id.has_value ());
1726
+ if (inst_id == SemIR::ErrorInst::InstId) {
1727
+ return false ;
1728
+ }
1729
+ CARBON_CHECK (IsClangDeclImported (context, decl));
1730
+ }
1731
+ }
1732
+
1733
+ return true ;
1734
+ }
1735
+
1681
1736
// Imports a declaration from Clang to Carbon. If successful, returns the
1682
- // instruction for the new Carbon declaration. All unimported dependencies would
1683
- // be imported first.
1737
+ // instruction for the new Carbon declaration. All unimported dependencies are
1738
+ // imported first.
1684
1739
static auto ImportDeclAndDependencies (Context& context, SemIR::LocId loc_id,
1685
1740
clang::Decl* clang_decl)
1686
1741
-> SemIR::InstId {
1687
- // Collect dependencies.
1688
- llvm::SetVector<clang::Decl*> clang_decls;
1689
- clang_decls.insert (clang_decl);
1690
- for (size_t i = 0 ; i < clang_decls.size (); ++i) {
1691
- AddDependentUnimportedDecls (context, clang_decls[i], clang_decls);
1692
- }
1693
-
1694
- // Import dependencies in reverse order.
1695
- auto inst_id = SemIR::InstId::None;
1696
- for (clang::Decl* clang_decl_to_import : llvm::reverse (clang_decls)) {
1697
- inst_id =
1698
- ImportDeclAfterDependencies (context, loc_id, clang_decl_to_import);
1699
- if (!inst_id.has_value ()) {
1700
- break ;
1701
- }
1742
+ // Collect dependencies by walking the dependency graph in depth-first order.
1743
+ ImportWorklist worklist;
1744
+ AddDependentDecl (context, clang_decl, worklist);
1745
+ if (!ImportDeclSet (context, loc_id, worklist)) {
1746
+ return SemIR::ErrorInst::InstId;
1702
1747
}
1748
+ return LookupClangDeclInstId (context, clang_decl);
1749
+ }
1703
1750
1704
- return inst_id;
1751
+ // Imports a type from Clang to Carbon. If successful, returns the imported
1752
+ // TypeId. All unimported dependencies are imported first.
1753
+ static auto ImportTypeAndDependencies (Context& context, SemIR::LocId loc_id,
1754
+ clang::QualType type) -> TypeExpr {
1755
+ // Collect dependencies by walking the dependency graph in depth-first order.
1756
+ ImportWorklist worklist;
1757
+ AddDependentUnimportedTypeDecls (context, type, worklist);
1758
+ if (!ImportDeclSet (context, loc_id, worklist)) {
1759
+ return {.inst_id = SemIR::ErrorInst::TypeInstId,
1760
+ .type_id = SemIR::ErrorInst::TypeId};
1761
+ }
1762
+ return MapType (context, loc_id, type);
1705
1763
}
1706
1764
1707
1765
// Maps `clang::AccessSpecifier` to `SemIR::AccessKind`.
0 commit comments