diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2421,7 +2421,8 @@ /// Get or compute information about the layout of the specified /// record (struct/union/class) \p D, which indicates its size and field /// position information. - const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const; + const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D, + bool NoCache = false) const; /// Get or compute information about the layout of the specified /// Objective-C interface. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -3166,6 +3166,9 @@ if (FD->getParent()->isInvalidDecl()) return false; RL = &Info.Ctx.getASTRecordLayout(FD->getParent()); } + if (FD->getFieldIndex() >= RL->getFieldCount()) { + RL = &Info.Ctx.getASTRecordLayout(FD->getParent(), /* NoCache = */ true); + } unsigned I = FD->getFieldIndex(); LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I))); diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -3279,7 +3279,7 @@ /// specified record (struct/union/class), which indicates its size and field /// position information. const ASTRecordLayout & -ASTContext::getASTRecordLayout(const RecordDecl *D) const { +ASTContext::getASTRecordLayout(const RecordDecl *D, bool NoCache) const { // These asserts test different things. A record has a definition // as soon as we begin to parse the definition. That definition is // not a complete definition (which is what isDefinition() tests) @@ -3298,8 +3298,10 @@ // Look up this layout, if already laid out, return what we have. // Note that we can't save a reference to the entry because this function // is recursive. - const ASTRecordLayout *Entry = ASTRecordLayouts[D]; - if (Entry) return *Entry; + if (!NoCache) { + const ASTRecordLayout *Entry = ASTRecordLayouts[D]; + if (Entry) return *Entry; + } const ASTRecordLayout *NewEntry = nullptr; diff --git a/clang/test/Analysis/astimport-force-relayout/Inputs/api.cc b/clang/test/Analysis/astimport-force-relayout/Inputs/api.cc new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/astimport-force-relayout/Inputs/api.cc @@ -0,0 +1,31 @@ +#include "v8.h" + +typedef long int intptr_t; + +namespace v8 { + +class Deoptimizer { +public: + static int input_offset() { + return (reinterpret_cast( + &(reinterpret_cast(16)->input_)) - + 16); + } + + static int output_count_offset() { + return (reinterpret_cast( + &(reinterpret_cast(16)->output_count_)) - + 16); + } + +private: + int input_; + int output_count_; +}; + +Local Function::NewInstance(Local context, int argc, + Local argv[]) const { + return NewInstanceWithSideEffectType(context, argc, argv); +} + +} // namespace v8 diff --git a/clang/test/Analysis/astimport-force-relayout/Inputs/externalDefMap.txt b/clang/test/Analysis/astimport-force-relayout/Inputs/externalDefMap.txt new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/astimport-force-relayout/Inputs/externalDefMap.txt @@ -0,0 +1,3 @@ +45:c:@N@v8@S@Deoptimizer@F@output_count_offset#S api.cc.ast +38:c:@N@v8@S@Deoptimizer@F@input_offset#S api.cc.ast +101:c:@N@v8@S@Function@F@NewInstance#$@N@v8@S@Local>#$@N@v8@S@Context#I#*$@N@v8@S@Local>#$@N@v8@S@Value#1 api.cc.ast diff --git a/clang/test/Analysis/astimport-force-relayout/Inputs/v8.h b/clang/test/Analysis/astimport-force-relayout/Inputs/v8.h new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/astimport-force-relayout/Inputs/v8.h @@ -0,0 +1,28 @@ +#ifndef INCLUDE_V8_H_ +#define INCLUDE_V8_H_ + +namespace v8 { + +class Context; +class Object; +class Value; + +template +class Local {}; + +class Function { + public: + Local NewInstance(Local context, int argc, + Local argv[]) const; + + Local NewInstance(Local context) const { + return NewInstance(context, 0, nullptr); + } + + Local NewInstanceWithSideEffectType(Local context, int argc, + Local argv[]) const; +}; + +} // namespace v8 + +#endif // INCLUDE_V8_H_ diff --git a/clang/test/Analysis/astimport-force-relayout/date.cpp b/clang/test/Analysis/astimport-force-relayout/date.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/astimport-force-relayout/date.cpp @@ -0,0 +1,20 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: mkdir -p %t/ctudir + +// RUN: %clang -c -mthumb --target=armv7a-linux-androideabi10000 -x c++ \ +// RUN: -std=gnu++17 %p/Inputs/api.cc -emit-ast -o %t/ctudir/api.cc.ast + +// RUN: cp %p/Inputs/externalDefMap.txt %t/ctudir/externalDefMap.txt + +// RUN: %clang_analyze_cc1 -triple thumbv7-unknown-linux-android10000 \ +// RUN: -std=gnu++17 \ +// RUN: -analyzer-checker=core.DivideZero \ +// RUN: -analyzer-opt-analyze-headers \ +// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ +// RUN: -analyzer-config ctu-dir=%t/ctudir \ +// RUN: -analyzer-config display-ctu-progress=true \ +// RUN: -fno-signed-char %s + +// expected-no-diagnostics + +#include "Inputs/v8.h"