From 9cb8254600694de327fd73ae02dac216c9e81c64 Mon Sep 17 00:00:00 2001 From: naveen-seth Date: Tue, 4 Nov 2025 00:58:22 +0100 Subject: [PATCH] [clang][modules] Fix crash in enum visibility lookup for C++20 header units Fixes #165445. Fixes a crash when ASTWriter::GenerateNameLookupTable processes enum constants from C++20 header units. The special handling for enum constants, introduced in fccc6ee, doesn't account for declarations whose owning module is a C++20 header unit. It calls isNamedModule() on the result of getTopLevelOwningNamedModule(), which returns null for header units, causing a null pointer dereference. --- clang/lib/Serialization/ASTWriter.cpp | 3 +- ...rash-enum-visibility-with-header-unit.cppm | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 clang/test/Modules/crash-enum-visibility-with-header-unit.cppm diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 3ac338e013deb..b1fd151790d96 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4374,8 +4374,7 @@ class ASTDeclContextNameLookupTrait // parent of parent. We DON'T remove the enum constant from its parent. So // we don't need to care about merging problems here. if (auto *ECD = dyn_cast(D); - ECD && DC.isFileContext() && ECD->getOwningModule() && - ECD->getTopLevelOwningNamedModule()->isNamedModule()) { + ECD && DC.isFileContext() && ECD->getTopLevelOwningNamedModule()) { if (llvm::all_of( DC.noload_lookup( cast(ECD->getDeclContext())->getDeclName()), diff --git a/clang/test/Modules/crash-enum-visibility-with-header-unit.cppm b/clang/test/Modules/crash-enum-visibility-with-header-unit.cppm new file mode 100644 index 0000000000000..90c57796dcf7e --- /dev/null +++ b/clang/test/Modules/crash-enum-visibility-with-header-unit.cppm @@ -0,0 +1,46 @@ +// Fixes #165445 + +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -x c++-user-header %t/header.h \ +// RUN: -emit-header-unit -o %t/header.pcm +// +// RUN: %clang_cc1 -std=c++20 %t/A.cppm -fmodule-file=%t/header.pcm \ +// RUN: -emit-module-interface -o %t/A.pcm +// +// RUN: %clang_cc1 -std=c++20 %t/B.cppm -fmodule-file=%t/header.pcm \ +// RUN: -emit-module-interface -o %t/B.pcm +// +// RUN: %clang_cc1 -std=c++20 %t/use.cpp \ +// RUN: -fmodule-file=A=%t/A.pcm -fmodule-file=B=%t/B.pcm \ +// RUN: -fmodule-file=%t/header.pcm \ +// RUN: -verify -fsyntax-only + +//--- enum.h +enum E { Value }; + +//--- header.h +#include "enum.h" + +//--- A.cppm +module; +#include "enum.h" +export module A; + +auto e = Value; + +//--- B.cppm +export module B; +import "header.h"; + +auto e = Value; + +//--- use.cpp +// expected-no-diagnostics +import A; +import B; +#include "enum.h" + +auto e = Value;