aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorAndy Kaylor <akaylor@nvidia.com>2025-06-06 12:54:43 -0700
committerGitHub <noreply@github.com>2025-06-06 12:54:43 -0700
commit16dda4d3f4051c449f59f98b69dddddf06b4648c (patch)
tree0e7eb2cefacb12b59422d2a577189f5ac43b86b8 /clang/lib
parent107601ed063f9e92aba61ea4f2a36c372127a82a (diff)
downloadllvm-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.cpp6
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.h3
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenTypes.cpp39
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenTypes.h4
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenerator.cpp23
-rw-r--r--clang/lib/CIR/FrontendAction/CIRGenAction.cpp7
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);
}