diff options
author | Andy Kaylor <akaylor@nvidia.com> | 2025-06-06 12:54:43 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-06 12:54:43 -0700 |
commit | 16dda4d3f4051c449f59f98b69dddddf06b4648c (patch) | |
tree | 0e7eb2cefacb12b59422d2a577189f5ac43b86b8 /clang/lib | |
parent | 107601ed063f9e92aba61ea4f2a36c372127a82a (diff) | |
download | llvm-16dda4d3f4051c449f59f98b69dddddf06b4648c.zip llvm-16dda4d3f4051c449f59f98b69dddddf06b4648c.tar.gz llvm-16dda4d3f4051c449f59f98b69dddddf06b4648c.tar.bz2 |
[CIR] Add support for completing forward-declared types (#143176)
This adds the needed handling for completing record types which were
previously declared leading us to create an incomplete record type.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenModule.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenModule.h | 3 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 39 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenTypes.h | 4 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenerator.cpp | 23 | ||||
-rw-r--r-- | clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 7 |
6 files changed, 80 insertions, 2 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index ce3c57e..e5eae31 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -838,6 +838,11 @@ void CIRGenModule::maybeSetTrivialComdat(const Decl &d, mlir::Operation *op) { assert(!cir::MissingFeatures::opFuncSetComdat()); } +void CIRGenModule::updateCompletedType(const TagDecl *td) { + // Make sure that this type is translated. + genTypes.updateCompletedType(td); +} + // TODO(CIR): this could be a common method between LLVM codegen. static bool isVarDeclStrongDefinition(const ASTContext &astContext, CIRGenModule &cgm, const VarDecl *vd, @@ -1145,6 +1150,7 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { // No code generation needed. case Decl::UsingShadow: + case Decl::Empty: break; // C++ Decls diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 7055170..ac25d52 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -241,6 +241,9 @@ public: void emitTentativeDefinition(const VarDecl *d); + // Make sure that this type is translated. + void updateCompletedType(const clang::TagDecl *td); + bool supportsCOMDAT() const; void maybeSetTrivialComdat(const clang::Decl &d, mlir::Operation *op); diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 5f51d34..eaba3df 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -432,8 +432,6 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } case Type::Enum: { - // TODO(cir): Implement updateCompletedType for enums. - assert(!cir::MissingFeatures::updateCompletedType()); const EnumDecl *ED = cast<EnumType>(ty)->getDecl(); if (auto integerType = ED->getIntegerType(); !integerType.isNull()) return convertType(integerType); @@ -586,3 +584,40 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeGlobalDeclaration(GlobalDecl gd) { return arrangeFunctionDeclaration(fd); } + +// When we find the full definition for a TagDecl, replace the 'opaque' type we +// previously made for it if applicable. +void CIRGenTypes::updateCompletedType(const TagDecl *td) { + // If this is an enum being completed, then we flush all non-struct types + // from the cache. This allows function types and other things that may be + // derived from the enum to be recomputed. + if (const auto *ed = dyn_cast<EnumDecl>(td)) { + // Classic codegen clears the type cache if it contains an entry for this + // enum type that doesn't use i32 as the underlying type, but I can't find + // a test case that meets that condition. C++ doesn't allow forward + // declaration of enums, and C doesn't allow an incomplete forward + // declaration with a non-default type. + assert( + !typeCache.count(ed->getTypeForDecl()) || + (convertType(ed->getIntegerType()) == typeCache[ed->getTypeForDecl()])); + // If necessary, provide the full definition of a type only used with a + // declaration so far. + assert(!cir::MissingFeatures::generateDebugInfo()); + return; + } + + // If we completed a RecordDecl that we previously used and converted to an + // anonymous type, then go ahead and complete it now. + const auto *rd = cast<RecordDecl>(td); + if (rd->isDependentType()) + return; + + // Only complete if we converted it already. If we haven't converted it yet, + // we'll just do it lazily. + if (recordDeclTypes.count(astContext.getTagDeclType(rd).getTypePtr())) + convertRecordDeclType(rd); + + // If necessary, provide the full definition of a type only used with a + // declaration so far. + assert(!cir::MissingFeatures::generateDebugInfo()); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 7a4301e..48d474b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -151,6 +151,10 @@ public: const CIRGenFunctionInfo &arrangeGlobalDeclaration(GlobalDecl gd); + /// UpdateCompletedType - when we find the full definition for a TagDecl, + /// replace the 'opaque' type we previously made for it if applicable. + void updateCompletedType(const clang::TagDecl *td); + /// Free functions are functions that are compatible with an ordinary C /// function pointer type. const CIRGenFunctionInfo & diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index 0503b49..99d6528 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -129,6 +129,29 @@ void CIRGenerator::emitDeferredDecls() { deferredInlineMemberFuncDefs.clear(); } +/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl to +/// (e.g. struct, union, enum, class) is completed. This allows the client to +/// hack on the type, which can occur at any point in the file (because these +/// can be defined in declspecs). +void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) { + if (diags.hasErrorOccurred()) + return; + + // Don't allow re-entrant calls to CIRGen triggered by PCH deserialization to + // emit deferred decls. + HandlingTopLevelDeclRAII handlingDecl(*this, /*EmitDeferred=*/false); + + cgm->updateCompletedType(d); + + // For MSVC compatibility, treat declarations of static data members with + // inline initializers as definitions. + if (astContext->getTargetInfo().getCXXABI().isMicrosoft()) + cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: MSABI"); + // For OpenMP emit declare reduction functions, if required. + if (astContext->getLangOpts().OpenMP) + cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: OpenMP"); +} + void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) { if (diags.hasErrorOccurred()) return; diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index c19312a..9264aa6 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -140,6 +140,13 @@ public: } } + void HandleTagDeclDefinition(TagDecl *D) override { + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + Context->getSourceManager(), + "CIR generation of declaration"); + Gen->HandleTagDeclDefinition(D); + } + void CompleteTentativeDefinition(VarDecl *D) override { Gen->CompleteTentativeDefinition(D); } |