diff --git a/core/metacling/src/ClingRAII.h b/core/metacling/src/ClingRAII.h index cce753ced1266..9a9a38955bdb5 100644 --- a/core/metacling/src/ClingRAII.h +++ b/core/metacling/src/ClingRAII.h @@ -26,15 +26,24 @@ namespace ROOT { decltype(clang::Sema::MaybeODRUseExprs) fMaybeODRUseExprs; decltype(clang::Sema::FunctionScopes) fFunctionScopes; decltype(clang::Sema::UndefinedButUsed) fUndefinedButUsed; + // The start indices into FunctionScopes and InventedParameterInfos must + // follow the swap: when we are called during a template instantiation, + // Sema::ContextRAII has set them to the depth of the outer stack, which + // is past the end of our fresh FunctionScopes. + decltype(clang::Sema::FunctionScopesStart) fFunctionScopesStart = 0; + decltype(clang::Sema::InventedParameterInfosStart) fInventedParameterInfosStart; // Set by the constructor to the size of Sema::InventedParameterInfos clang::Sema& fSema; void Swapem() { std::swap(fCleanup, fSema.Cleanup); std::swap(fExprCleanupObjects, fSema.ExprCleanupObjects); std::swap(fMaybeODRUseExprs, fSema.MaybeODRUseExprs); std::swap(fFunctionScopes, fSema.FunctionScopes); + std::swap(fFunctionScopesStart, fSema.FunctionScopesStart); + std::swap(fInventedParameterInfosStart, fSema.InventedParameterInfosStart); std::swap(fUndefinedButUsed, fSema.UndefinedButUsed); } - SemaExprCleanupsRAII(clang::Sema& S): fSema(S) { + SemaExprCleanupsRAII(clang::Sema& S): + fInventedParameterInfosStart(S.InventedParameterInfos.size()), fSema(S) { fFunctionScopes.push_back(new clang::sema::FunctionScopeInfo(S.Diags)); Swapem(); }; diff --git a/roottest/root/meta/autoloading/nestedAutoParse/CMakeLists.txt b/roottest/root/meta/autoloading/nestedAutoParse/CMakeLists.txt new file mode 100644 index 0000000000000..48b39123762ac --- /dev/null +++ b/roottest/root/meta/autoloading/nestedAutoParse/CMakeLists.txt @@ -0,0 +1,11 @@ +ROOTTEST_GENERATE_REFLEX_DICTIONARY(nestedAutoParse + nestedAutoParse.h + SELECTION selection.xml + LIBNAME libnestedAutoParse_dictrflx + NO_ROOTMAP + FIXTURES_SETUP root-meta-autoloading-nestedAutoParse-fixture) + +ROOTTEST_ADD_TEST(nestedAutoParse + MACRO execNestedAutoParse.C + COPY_TO_BUILDDIR useNestedAutoParse.C + FIXTURES_REQUIRED root-meta-autoloading-nestedAutoParse-fixture) diff --git a/roottest/root/meta/autoloading/nestedAutoParse/execNestedAutoParse.C b/roottest/root/meta/autoloading/nestedAutoParse/execNestedAutoParse.C new file mode 100644 index 0000000000000..3a9ae471b7fbd --- /dev/null +++ b/roottest/root/meta/autoloading/nestedAutoParse/execNestedAutoParse.C @@ -0,0 +1,15 @@ +// Autoparsing a payload from within a template instantiation used to crash in +// Sema::EnterTemplatedContext, because the nested parse saw the function scopes +// of the outer instantiation (Sema::FunctionScopesStart was not reset). +int execNestedAutoParse() +{ + // Registers only the forward declaration of Payload; its definition is + // parsed on demand. + if (gSystem->Load("libnestedAutoParse_dictrflx") < 0) + return 1; + // Use ProcessLine rather than TInterpreter::Declare: Declare suspends + // autoparsing. + if (gROOT->ProcessLine(".L useNestedAutoParse.C") != 0) + return 2; + return gROOT->ProcessLine("useNestedAutoParse();") == 42 ? 0 : 3; +} diff --git a/roottest/root/meta/autoloading/nestedAutoParse/nestedAutoParse.h b/roottest/root/meta/autoloading/nestedAutoParse/nestedAutoParse.h new file mode 100644 index 0000000000000..646a1648ffbb2 --- /dev/null +++ b/roottest/root/meta/autoloading/nestedAutoParse/nestedAutoParse.h @@ -0,0 +1,22 @@ +#ifndef ROOTTEST_NESTEDAUTOPARSE_H +#define ROOTTEST_NESTEDAUTOPARSE_H + +namespace NestedAutoParse { +namespace Inner { + +// Declaring a class template while parsing the payload calls +// Sema::EnterTemplatedContext, which walks Sema's function scopes. +template +struct Tmpl { + static constexpr int value = N; +}; + +struct Payload { + int fValue = 42; + int get() const { return fValue + Tmpl<0>::value; } +}; + +} // namespace Inner +} // namespace NestedAutoParse + +#endif diff --git a/roottest/root/meta/autoloading/nestedAutoParse/selection.xml b/roottest/root/meta/autoloading/nestedAutoParse/selection.xml new file mode 100644 index 0000000000000..2a09e895e640b --- /dev/null +++ b/roottest/root/meta/autoloading/nestedAutoParse/selection.xml @@ -0,0 +1,3 @@ + + + diff --git a/roottest/root/meta/autoloading/nestedAutoParse/useNestedAutoParse.C b/roottest/root/meta/autoloading/nestedAutoParse/useNestedAutoParse.C new file mode 100644 index 0000000000000..6a34b0350be3a --- /dev/null +++ b/roottest/root/meta/autoloading/nestedAutoParse/useNestedAutoParse.C @@ -0,0 +1,10 @@ +#include + +int useNestedAutoParse() +{ + // Payload is only forward declared here. Instantiating the members of + // std::vector needs the complete type, so its payload is + // autoparsed from within a template instantiation. + std::vector v(1); + return v[0].get(); +}