Commit a7f99c8ee9

Andrew Kelley <andrew@ziglang.org>
2019-04-30 06:21:45
self-hosted translate-c: iterate over top level decls
See #1964
1 parent 01365be
src/translate_c.cpp
@@ -4554,28 +4554,27 @@ static void visit_var_decl(Context *c, const clang::VarDecl *var_decl) {
     return;
 }
 
-static bool decl_visitor(void *context, const ZigClangDecl *zdecl) {
-    const clang::Decl *decl = reinterpret_cast<const clang::Decl *>(zdecl);
+static bool decl_visitor(void *context, const ZigClangDecl *decl) {
     Context *c = (Context*)context;
 
-    switch (decl->getKind()) {
-        case clang::Decl::Function:
-            visit_fn_decl(c, static_cast<const clang::FunctionDecl*>(decl));
+    switch (ZigClangDecl_getKind(decl)) {
+        case ZigClangDeclFunction:
+            visit_fn_decl(c, reinterpret_cast<const clang::FunctionDecl*>(decl));
             break;
-        case clang::Decl::Typedef:
+        case ZigClangDeclTypedef:
             resolve_typedef_decl(c, reinterpret_cast<const ZigClangTypedefNameDecl *>(decl));
             break;
-        case clang::Decl::Enum:
+        case ZigClangDeclEnum:
             resolve_enum_decl(c, reinterpret_cast<const ZigClangEnumDecl *>(decl));
             break;
-        case clang::Decl::Record:
-            resolve_record_decl(c, (const ZigClangRecordDecl *)(decl));
+        case ZigClangDeclRecord:
+            resolve_record_decl(c, reinterpret_cast<const ZigClangRecordDecl *>(decl));
             break;
-        case clang::Decl::Var:
-            visit_var_decl(c, static_cast<const clang::VarDecl *>(decl));
+        case ZigClangDeclVar:
+            visit_var_decl(c, reinterpret_cast<const clang::VarDecl *>(decl));
             break;
         default:
-            emit_warning(c, bitcast(decl->getLocation()), "ignoring %s decl", decl->getDeclKindName());
+            emit_warning(c, ZigClangDecl_getLocation(decl), "ignoring %s decl", ZigClangDecl_getDeclKindName(decl));
     }
 
     return true;
src/zig_clang.cpp
@@ -799,6 +799,162 @@ static_assert((clang::APValue::ValueKind)ZigClangAPValueMemberPointer == clang::
 static_assert((clang::APValue::ValueKind)ZigClangAPValueAddrLabelDiff == clang::APValue::AddrLabelDiff, "");
 
 
+void ZigClang_detect_enum_DeclKind(clang::Decl::Kind x) {
+    switch (x) {
+        case ZigClangDeclAccessSpec:
+        case ZigClangDeclBlock:
+        case ZigClangDeclCaptured:
+        case ZigClangDeclClassScopeFunctionSpecialization:
+        case ZigClangDeclEmpty:
+        case ZigClangDeclExport:
+        case ZigClangDeclExternCContext:
+        case ZigClangDeclFileScopeAsm:
+        case ZigClangDeclFriend:
+        case ZigClangDeclFriendTemplate:
+        case ZigClangDeclImport:
+        case ZigClangDeclLinkageSpec:
+        case ZigClangDeclLabel:
+        case ZigClangDeclNamespace:
+        case ZigClangDeclNamespaceAlias:
+        case ZigClangDeclObjCCompatibleAlias:
+        case ZigClangDeclObjCCategory:
+        case ZigClangDeclObjCCategoryImpl:
+        case ZigClangDeclObjCImplementation:
+        case ZigClangDeclObjCInterface:
+        case ZigClangDeclObjCProtocol:
+        case ZigClangDeclObjCMethod:
+        case ZigClangDeclObjCProperty:
+        case ZigClangDeclBuiltinTemplate:
+        case ZigClangDeclClassTemplate:
+        case ZigClangDeclFunctionTemplate:
+        case ZigClangDeclTypeAliasTemplate:
+        case ZigClangDeclVarTemplate:
+        case ZigClangDeclTemplateTemplateParm:
+        case ZigClangDeclEnum:
+        case ZigClangDeclRecord:
+        case ZigClangDeclCXXRecord:
+        case ZigClangDeclClassTemplateSpecialization:
+        case ZigClangDeclClassTemplatePartialSpecialization:
+        case ZigClangDeclTemplateTypeParm:
+        case ZigClangDeclObjCTypeParam:
+        case ZigClangDeclTypeAlias:
+        case ZigClangDeclTypedef:
+        case ZigClangDeclUnresolvedUsingTypename:
+        case ZigClangDeclUsing:
+        case ZigClangDeclUsingDirective:
+        case ZigClangDeclUsingPack:
+        case ZigClangDeclUsingShadow:
+        case ZigClangDeclConstructorUsingShadow:
+        case ZigClangDeclBinding:
+        case ZigClangDeclField:
+        case ZigClangDeclObjCAtDefsField:
+        case ZigClangDeclObjCIvar:
+        case ZigClangDeclFunction:
+        case ZigClangDeclCXXDeductionGuide:
+        case ZigClangDeclCXXMethod:
+        case ZigClangDeclCXXConstructor:
+        case ZigClangDeclCXXConversion:
+        case ZigClangDeclCXXDestructor:
+        case ZigClangDeclMSProperty:
+        case ZigClangDeclNonTypeTemplateParm:
+        case ZigClangDeclVar:
+        case ZigClangDeclDecomposition:
+        case ZigClangDeclImplicitParam:
+        case ZigClangDeclOMPCapturedExpr:
+        case ZigClangDeclParmVar:
+        case ZigClangDeclVarTemplateSpecialization:
+        case ZigClangDeclVarTemplatePartialSpecialization:
+        case ZigClangDeclEnumConstant:
+        case ZigClangDeclIndirectField:
+        case ZigClangDeclOMPDeclareReduction:
+        case ZigClangDeclUnresolvedUsingValue:
+        case ZigClangDeclOMPRequires:
+        case ZigClangDeclOMPThreadPrivate:
+        case ZigClangDeclObjCPropertyImpl:
+        case ZigClangDeclPragmaComment:
+        case ZigClangDeclPragmaDetectMismatch:
+        case ZigClangDeclStaticAssert:
+        case ZigClangDeclTranslationUnit:
+            break;
+    }
+}
+
+static_assert((clang::Decl::Kind)ZigClangDeclAccessSpec == clang::Decl::AccessSpec, "");
+static_assert((clang::Decl::Kind)ZigClangDeclBlock == clang::Decl::Block, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCaptured == clang::Decl::Captured, "");
+static_assert((clang::Decl::Kind)ZigClangDeclClassScopeFunctionSpecialization == clang::Decl::ClassScopeFunctionSpecialization, "");
+static_assert((clang::Decl::Kind)ZigClangDeclEmpty == clang::Decl::Empty, "");
+static_assert((clang::Decl::Kind)ZigClangDeclExport == clang::Decl::Export, "");
+static_assert((clang::Decl::Kind)ZigClangDeclExternCContext == clang::Decl::ExternCContext, "");
+static_assert((clang::Decl::Kind)ZigClangDeclFileScopeAsm == clang::Decl::FileScopeAsm, "");
+static_assert((clang::Decl::Kind)ZigClangDeclFriend == clang::Decl::Friend, "");
+static_assert((clang::Decl::Kind)ZigClangDeclFriendTemplate == clang::Decl::FriendTemplate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclImport == clang::Decl::Import, "");
+static_assert((clang::Decl::Kind)ZigClangDeclLinkageSpec == clang::Decl::LinkageSpec, "");
+static_assert((clang::Decl::Kind)ZigClangDeclLabel == clang::Decl::Label, "");
+static_assert((clang::Decl::Kind)ZigClangDeclNamespace == clang::Decl::Namespace, "");
+static_assert((clang::Decl::Kind)ZigClangDeclNamespaceAlias == clang::Decl::NamespaceAlias, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCCompatibleAlias == clang::Decl::ObjCCompatibleAlias, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCCategory == clang::Decl::ObjCCategory, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCCategoryImpl == clang::Decl::ObjCCategoryImpl, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCImplementation == clang::Decl::ObjCImplementation, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCInterface == clang::Decl::ObjCInterface, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCProtocol == clang::Decl::ObjCProtocol, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCMethod == clang::Decl::ObjCMethod, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCProperty == clang::Decl::ObjCProperty, "");
+static_assert((clang::Decl::Kind)ZigClangDeclBuiltinTemplate == clang::Decl::BuiltinTemplate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclClassTemplate == clang::Decl::ClassTemplate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclFunctionTemplate == clang::Decl::FunctionTemplate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclTypeAliasTemplate == clang::Decl::TypeAliasTemplate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclVarTemplate == clang::Decl::VarTemplate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclTemplateTemplateParm == clang::Decl::TemplateTemplateParm, "");
+static_assert((clang::Decl::Kind)ZigClangDeclEnum == clang::Decl::Enum, "");
+static_assert((clang::Decl::Kind)ZigClangDeclRecord == clang::Decl::Record, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCXXRecord == clang::Decl::CXXRecord, "");
+static_assert((clang::Decl::Kind)ZigClangDeclClassTemplateSpecialization == clang::Decl::ClassTemplateSpecialization, "");
+static_assert((clang::Decl::Kind)ZigClangDeclClassTemplatePartialSpecialization == clang::Decl::ClassTemplatePartialSpecialization, "");
+static_assert((clang::Decl::Kind)ZigClangDeclTemplateTypeParm == clang::Decl::TemplateTypeParm, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCTypeParam == clang::Decl::ObjCTypeParam, "");
+static_assert((clang::Decl::Kind)ZigClangDeclTypeAlias == clang::Decl::TypeAlias, "");
+static_assert((clang::Decl::Kind)ZigClangDeclTypedef == clang::Decl::Typedef, "");
+static_assert((clang::Decl::Kind)ZigClangDeclUnresolvedUsingTypename == clang::Decl::UnresolvedUsingTypename, "");
+static_assert((clang::Decl::Kind)ZigClangDeclUsing == clang::Decl::Using, "");
+static_assert((clang::Decl::Kind)ZigClangDeclUsingDirective == clang::Decl::UsingDirective, "");
+static_assert((clang::Decl::Kind)ZigClangDeclUsingPack == clang::Decl::UsingPack, "");
+static_assert((clang::Decl::Kind)ZigClangDeclUsingShadow == clang::Decl::UsingShadow, "");
+static_assert((clang::Decl::Kind)ZigClangDeclConstructorUsingShadow == clang::Decl::ConstructorUsingShadow, "");
+static_assert((clang::Decl::Kind)ZigClangDeclBinding == clang::Decl::Binding, "");
+static_assert((clang::Decl::Kind)ZigClangDeclField == clang::Decl::Field, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCAtDefsField == clang::Decl::ObjCAtDefsField, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCIvar == clang::Decl::ObjCIvar, "");
+static_assert((clang::Decl::Kind)ZigClangDeclFunction == clang::Decl::Function, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCXXDeductionGuide == clang::Decl::CXXDeductionGuide, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCXXMethod == clang::Decl::CXXMethod, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCXXConstructor == clang::Decl::CXXConstructor, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCXXConversion == clang::Decl::CXXConversion, "");
+static_assert((clang::Decl::Kind)ZigClangDeclCXXDestructor == clang::Decl::CXXDestructor, "");
+static_assert((clang::Decl::Kind)ZigClangDeclMSProperty == clang::Decl::MSProperty, "");
+static_assert((clang::Decl::Kind)ZigClangDeclNonTypeTemplateParm == clang::Decl::NonTypeTemplateParm, "");
+static_assert((clang::Decl::Kind)ZigClangDeclVar == clang::Decl::Var, "");
+static_assert((clang::Decl::Kind)ZigClangDeclDecomposition == clang::Decl::Decomposition, "");
+static_assert((clang::Decl::Kind)ZigClangDeclImplicitParam == clang::Decl::ImplicitParam, "");
+static_assert((clang::Decl::Kind)ZigClangDeclOMPCapturedExpr == clang::Decl::OMPCapturedExpr, "");
+static_assert((clang::Decl::Kind)ZigClangDeclParmVar == clang::Decl::ParmVar, "");
+static_assert((clang::Decl::Kind)ZigClangDeclVarTemplateSpecialization == clang::Decl::VarTemplateSpecialization, "");
+static_assert((clang::Decl::Kind)ZigClangDeclVarTemplatePartialSpecialization == clang::Decl::VarTemplatePartialSpecialization, "");
+static_assert((clang::Decl::Kind)ZigClangDeclEnumConstant == clang::Decl::EnumConstant, "");
+static_assert((clang::Decl::Kind)ZigClangDeclIndirectField == clang::Decl::IndirectField, "");
+static_assert((clang::Decl::Kind)ZigClangDeclOMPDeclareReduction == clang::Decl::OMPDeclareReduction, "");
+static_assert((clang::Decl::Kind)ZigClangDeclUnresolvedUsingValue == clang::Decl::UnresolvedUsingValue, "");
+static_assert((clang::Decl::Kind)ZigClangDeclOMPRequires == clang::Decl::OMPRequires, "");
+static_assert((clang::Decl::Kind)ZigClangDeclOMPThreadPrivate == clang::Decl::OMPThreadPrivate, "");
+static_assert((clang::Decl::Kind)ZigClangDeclObjCPropertyImpl == clang::Decl::ObjCPropertyImpl, "");
+static_assert((clang::Decl::Kind)ZigClangDeclPragmaComment == clang::Decl::PragmaComment, "");
+static_assert((clang::Decl::Kind)ZigClangDeclPragmaDetectMismatch == clang::Decl::PragmaDetectMismatch, "");
+static_assert((clang::Decl::Kind)ZigClangDeclStaticAssert == clang::Decl::StaticAssert, "");
+static_assert((clang::Decl::Kind)ZigClangDeclTranslationUnit == clang::Decl::TranslationUnit, "");
+
+
 static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), "");
 static ZigClangSourceLocation bitcast(clang::SourceLocation src) {
     ZigClangSourceLocation dest;
@@ -946,6 +1102,16 @@ const char *ZigClangDecl_getName_bytes_begin(const ZigClangDecl *zig_decl) {
     return (const char *)named_decl->getName().bytes_begin();
 }
 
+ZigClangDeclKind ZigClangDecl_getKind(const struct ZigClangDecl *self) {
+    auto casted = reinterpret_cast<const clang::Decl *>(self);
+    return (ZigClangDeclKind)casted->getKind();
+}
+
+const char *ZigClangDecl_getDeclKindName(const struct ZigClangDecl *self) {
+    auto casted = reinterpret_cast<const clang::Decl *>(self);
+    return casted->getDeclKindName();
+}
+
 ZigClangSourceLocation ZigClangRecordDecl_getLocation(const ZigClangRecordDecl *zig_record_decl) {
     const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl);
     return bitcast(record_decl->getLocation());
@@ -961,6 +1127,11 @@ ZigClangSourceLocation ZigClangTypedefNameDecl_getLocation(const ZigClangTypedef
     return bitcast(casted->getLocation());
 }
 
+ZigClangSourceLocation ZigClangDecl_getLocation(const ZigClangDecl *self) {
+    auto casted = reinterpret_cast<const clang::Decl *>(self);
+    return bitcast(casted->getLocation());
+}
+
 bool ZigClangSourceLocation_eq(ZigClangSourceLocation zig_a, ZigClangSourceLocation zig_b) {
     clang::SourceLocation a = bitcast(zig_a);
     clang::SourceLocation b = bitcast(zig_b);
src/zig_clang.h
@@ -482,6 +482,83 @@ enum ZigClangAPValueKind {
     ZigClangAPValueAddrLabelDiff,
 };
 
+enum ZigClangDeclKind {
+    ZigClangDeclAccessSpec,
+    ZigClangDeclBlock,
+    ZigClangDeclCaptured,
+    ZigClangDeclClassScopeFunctionSpecialization,
+    ZigClangDeclEmpty,
+    ZigClangDeclExport,
+    ZigClangDeclExternCContext,
+    ZigClangDeclFileScopeAsm,
+    ZigClangDeclFriend,
+    ZigClangDeclFriendTemplate,
+    ZigClangDeclImport,
+    ZigClangDeclLinkageSpec,
+    ZigClangDeclLabel,
+    ZigClangDeclNamespace,
+    ZigClangDeclNamespaceAlias,
+    ZigClangDeclObjCCompatibleAlias,
+    ZigClangDeclObjCCategory,
+    ZigClangDeclObjCCategoryImpl,
+    ZigClangDeclObjCImplementation,
+    ZigClangDeclObjCInterface,
+    ZigClangDeclObjCProtocol,
+    ZigClangDeclObjCMethod,
+    ZigClangDeclObjCProperty,
+    ZigClangDeclBuiltinTemplate,
+    ZigClangDeclClassTemplate,
+    ZigClangDeclFunctionTemplate,
+    ZigClangDeclTypeAliasTemplate,
+    ZigClangDeclVarTemplate,
+    ZigClangDeclTemplateTemplateParm,
+    ZigClangDeclEnum,
+    ZigClangDeclRecord,
+    ZigClangDeclCXXRecord,
+    ZigClangDeclClassTemplateSpecialization,
+    ZigClangDeclClassTemplatePartialSpecialization,
+    ZigClangDeclTemplateTypeParm,
+    ZigClangDeclObjCTypeParam,
+    ZigClangDeclTypeAlias,
+    ZigClangDeclTypedef,
+    ZigClangDeclUnresolvedUsingTypename,
+    ZigClangDeclUsing,
+    ZigClangDeclUsingDirective,
+    ZigClangDeclUsingPack,
+    ZigClangDeclUsingShadow,
+    ZigClangDeclConstructorUsingShadow,
+    ZigClangDeclBinding,
+    ZigClangDeclField,
+    ZigClangDeclObjCAtDefsField,
+    ZigClangDeclObjCIvar,
+    ZigClangDeclFunction,
+    ZigClangDeclCXXDeductionGuide,
+    ZigClangDeclCXXMethod,
+    ZigClangDeclCXXConstructor,
+    ZigClangDeclCXXConversion,
+    ZigClangDeclCXXDestructor,
+    ZigClangDeclMSProperty,
+    ZigClangDeclNonTypeTemplateParm,
+    ZigClangDeclVar,
+    ZigClangDeclDecomposition,
+    ZigClangDeclImplicitParam,
+    ZigClangDeclOMPCapturedExpr,
+    ZigClangDeclParmVar,
+    ZigClangDeclVarTemplateSpecialization,
+    ZigClangDeclVarTemplatePartialSpecialization,
+    ZigClangDeclEnumConstant,
+    ZigClangDeclIndirectField,
+    ZigClangDeclOMPDeclareReduction,
+    ZigClangDeclUnresolvedUsingValue,
+    ZigClangDeclOMPRequires,
+    ZigClangDeclOMPThreadPrivate,
+    ZigClangDeclObjCPropertyImpl,
+    ZigClangDeclPragmaComment,
+    ZigClangDeclPragmaDetectMismatch,
+    ZigClangDeclStaticAssert,
+    ZigClangDeclTranslationUnit,
+};
+
 ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,
         struct ZigClangSourceLocation Loc);
 ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *,
@@ -520,6 +597,7 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const
 ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangRecordDecl_getLocation(const struct ZigClangRecordDecl *);
 ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangEnumDecl_getLocation(const struct ZigClangEnumDecl *);
 ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangTypedefNameDecl_getLocation(const struct ZigClangTypedefNameDecl *);
+ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDecl_getLocation(const struct ZigClangDecl *);
 
 ZIG_EXTERN_C bool ZigClangRecordDecl_isUnion(const struct ZigClangRecordDecl *record_decl);
 ZIG_EXTERN_C bool ZigClangRecordDecl_isStruct(const struct ZigClangRecordDecl *record_decl);
@@ -528,6 +606,8 @@ ZIG_EXTERN_C bool ZigClangRecordDecl_isAnonymousStructOrUnion(const struct ZigCl
 ZIG_EXTERN_C struct ZigClangQualType ZigClangEnumDecl_getIntegerType(const struct ZigClangEnumDecl *);
 
 ZIG_EXTERN_C const char *ZigClangDecl_getName_bytes_begin(const struct ZigClangDecl *decl);
+ZIG_EXTERN_C enum ZigClangDeclKind ZigClangDecl_getKind(const struct ZigClangDecl *decl);
+ZIG_EXTERN_C const char *ZigClangDecl_getDeclKindName(const struct ZigClangDecl *decl);
 
 ZIG_EXTERN_C bool ZigClangSourceLocation_eq(struct ZigClangSourceLocation a, struct ZigClangSourceLocation b);
 
@@ -543,7 +623,7 @@ ZIG_EXTERN_C bool ZigClangQualType_isVolatileQualified(struct ZigClangQualType);
 ZIG_EXTERN_C bool ZigClangQualType_isRestrictQualified(struct ZigClangQualType);
 
 ZIG_EXTERN_C enum ZigClangTypeClass ZigClangType_getTypeClass(const struct ZigClangType *self);
-ZIG_EXTERN_C ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self);
+ZIG_EXTERN_C struct ZigClangQualType ZigClangType_getPointeeType(const struct ZigClangType *self);
 ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
 ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
 
src-self-hosted/clang.zig
@@ -813,7 +813,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(arg0: ?*const struct_ZigCla
 pub extern fn ZigClangASTContext_getPointerType(arg0: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;
 pub extern fn ZigClangASTUnit_getASTContext(arg0: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
 pub extern fn ZigClangASTUnit_getSourceManager(arg0: ?*struct_ZigClangASTUnit) ?*struct_ZigClangSourceManager;
-pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(arg0: ?*struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, ?*const struct_ZigClangDecl) bool) bool;
+pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool;
 pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) ?*const struct_ZigClangRecordDecl;
 pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl;
 pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
@@ -967,3 +967,83 @@ pub extern fn ZigClangLoadFromCommandLine(
     errors_len: *usize,
     resources_path: [*c]const u8,
 ) ?*ZigClangASTUnit;
+
+
+pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;
+
+pub const ZigClangDeclKind = extern enum {
+    AccessSpec,
+    Block,
+    Captured,
+    ClassScopeFunctionSpecialization,
+    Empty,
+    Export,
+    ExternCContext,
+    FileScopeAsm,
+    Friend,
+    FriendTemplate,
+    Import,
+    LinkageSpec,
+    Label,
+    Namespace,
+    NamespaceAlias,
+    ObjCCompatibleAlias,
+    ObjCCategory,
+    ObjCCategoryImpl,
+    ObjCImplementation,
+    ObjCInterface,
+    ObjCProtocol,
+    ObjCMethod,
+    ObjCProperty,
+    BuiltinTemplate,
+    ClassTemplate,
+    FunctionTemplate,
+    TypeAliasTemplate,
+    VarTemplate,
+    TemplateTemplateParm,
+    Enum,
+    Record,
+    CXXRecord,
+    ClassTemplateSpecialization,
+    ClassTemplatePartialSpecialization,
+    TemplateTypeParm,
+    ObjCTypeParam,
+    TypeAlias,
+    Typedef,
+    UnresolvedUsingTypename,
+    Using,
+    UsingDirective,
+    UsingPack,
+    UsingShadow,
+    ConstructorUsingShadow,
+    Binding,
+    Field,
+    ObjCAtDefsField,
+    ObjCIvar,
+    Function,
+    CXXDeductionGuide,
+    CXXMethod,
+    CXXConstructor,
+    CXXConversion,
+    CXXDestructor,
+    MSProperty,
+    NonTypeTemplateParm,
+    Var,
+    Decomposition,
+    ImplicitParam,
+    OMPCapturedExpr,
+    ParmVar,
+    VarTemplateSpecialization,
+    VarTemplatePartialSpecialization,
+    EnumConstant,
+    IndirectField,
+    OMPDeclareReduction,
+    UnresolvedUsingValue,
+    OMPRequires,
+    OMPThreadPrivate,
+    ObjCPropertyImpl,
+    PragmaComment,
+    PragmaDetectMismatch,
+    StaticAssert,
+    TranslationUnit,
+};
src-self-hosted/translate_c.zig
@@ -1,5 +1,5 @@
 // This is the userland implementation of translate-c which will be used by both stage1
-// and stage2. Currently it's not used by anything, as it's not feature complete.
+// and stage2. Currently the only way it is used is with `zig translate-c-2`.
 
 const std = @import("std");
 const ast = std.zig.ast;
@@ -13,6 +13,16 @@ pub const Mode = enum {
 
 pub const ClangErrMsg = Stage2ErrorMsg;
 
+pub const Error = error {
+    OutOfMemory,
+};
+
+const Context = struct {
+    tree: *ast.Tree,
+    source_buffer: *std.Buffer,
+    err: Error,
+};
+
 pub fn translate(
     backing_allocator: *std.mem.Allocator,
     args_begin: [*]?[*]const u8,
@@ -57,23 +67,65 @@ pub fn translate(
 
     var source_buffer = try std.Buffer.initSize(arena, 0);
 
-    try appendToken(tree, &source_buffer, "// TODO: implement more than just an empty source file", .LineComment);
+    var context = Context{
+        .tree = tree,
+        .source_buffer = &source_buffer,
+        .err = undefined,
+    };
+
+    if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
+        return context.err;
+    }
 
-    try appendToken(tree, &source_buffer, "", .Eof);
+    try appendToken(&context, .Eof, "");
     tree.source = source_buffer.toOwnedSlice();
     return tree;
 }
 
-fn appendToken(tree: *ast.Tree, source_buffer: *std.Buffer, src_text: []const u8, token_id: Token.Id) !void {
-    const start_index = source_buffer.len();
-    try source_buffer.append(src_text);
-    const end_index = source_buffer.len();
-    const new_token = try tree.tokens.addOne();
+extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool {
+    const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
+    declVisitor(c, decl) catch |err| {
+        c.err = err;
+        return false;
+    };
+    return true;
+}
+
+fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
+    switch (ZigClangDecl_getKind(decl)) {
+        .Function => {
+            try appendToken(c, .LineComment, "// TODO translate function decl");
+        },
+        .Typedef => {
+            try appendToken(c, .LineComment, "// TODO translate typedef");
+        },
+        .Enum => {
+            try appendToken(c, .LineComment, "// TODO translate enum");
+        },
+        .Record => {
+            try appendToken(c, .LineComment, "// TODO translate struct");
+        },
+        .Var => {
+            try appendToken(c, .LineComment, "// TODO translate variable");
+        },
+        else => {
+            // TODO emit_warning(c, bitcast(decl->getLocation()), "ignoring %s decl", decl->getDeclKindName());
+            try appendToken(c, .LineComment, "// TODO translate unknown decl");
+        },
+    }
+}
+
+fn appendToken(c: *Context, token_id: Token.Id, src_text: []const u8) !void {
+    const start_index = c.source_buffer.len();
+    try c.source_buffer.append(src_text);
+    const end_index = c.source_buffer.len();
+    const new_token = try c.tree.tokens.addOne();
     new_token.* = Token{
         .id = token_id,
         .start = start_index,
         .end = end_index,
     };
+    try c.source_buffer.appendByte('\n');
 }
 
 pub fn freeErrors(errors: []ClangErrMsg) void {