diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 89d306fb94046..c59413abc352d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -1548,8 +1548,8 @@ class MemRegionManager { /// a specified FieldDecl. 'superRegion' corresponds to the containing /// memory region (which typically represents the memory representing /// a structure or class). - const FieldRegion *getFieldRegion(const FieldDecl *fd, - const SubRegion* superRegion); + const FieldRegion *getFieldRegion(const FieldDecl *FD, + const SubRegion *SuperRegion); const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, const SubRegion *superRegion) { diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 5f271963e3d09..f20e79ae675a4 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1268,10 +1268,10 @@ const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) { return getSubRegion(Sym, getHeapRegion()); } -const FieldRegion* -MemRegionManager::getFieldRegion(const FieldDecl *d, - const SubRegion* superRegion){ - return getSubRegion(d, superRegion); +const FieldRegion * +MemRegionManager::getFieldRegion(const FieldDecl *FD, + const SubRegion *SuperRegion) { + return getSubRegion(FD->getCanonicalDecl(), SuperRegion); } const ObjCIvarRegion* @@ -1704,16 +1704,23 @@ static RegionOffset calculateOffset(const MemRegion *R) { if (SymbolicOffsetBase) continue; - // Get the field number. - unsigned idx = 0; - for (RecordDecl::field_iterator FI = RD->field_begin(), - FE = RD->field_end(); FI != FE; ++FI, ++idx) { - if (FR->getDecl() == *FI) - break; + assert(FR->getDecl()->getCanonicalDecl() == FR->getDecl()); + auto MaybeFieldIdx = [FR, RD]() -> std::optional { + for (auto [Idx, Field] : llvm::enumerate(RD->fields())) { + if (FR->getDecl() == Field->getCanonicalDecl()) + return Idx; + } + return std::nullopt; + }(); + + if (!MaybeFieldIdx.has_value()) { + assert(false && "Field not found"); + goto Finish; // Invalid offset. } + const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(RD); // This is offset in bits. - Offset += Layout.getFieldOffset(idx); + Offset += Layout.getFieldOffset(MaybeFieldIdx.value()); break; } } diff --git a/clang/test/Analysis/modules/explicit-templ-inst-crash-in-modules.cppm b/clang/test/Analysis/modules/explicit-templ-inst-crash-in-modules.cppm new file mode 100644 index 0000000000000..6eec29c7187ba --- /dev/null +++ b/clang/test/Analysis/modules/explicit-templ-inst-crash-in-modules.cppm @@ -0,0 +1,35 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// DEFINE: %{common-flags}= -std=c++20 -I %t -fprebuilt-module-path=%t +// +// RUN: %clang_cc1 %{common-flags} %t/other.cppm -emit-module-interface -o %t/other.pcm +// RUN: %clang_analyze_cc1 -analyzer-checker=core %{common-flags} %t/entry.cppm -verify + + +//--- MyStruct.h +template struct MyStruct { + T data = 0; +}; +template struct MyStruct; // Explicit template instantiation. + +//--- other.cppm +module; +#include "MyStruct.h" +export module other; +static void implicit_instantiate_MyStruct() { + MyStruct var; + (void)var; +} + +//--- entry.cppm +// expected-no-diagnostics +module; +#include "MyStruct.h" +module other; + +void entry_point() { + MyStruct var; // no-crash + (void)var; +}