[clang] [Clang][Sema] Fix exception specification comparison for functions with different template depths (PR #111561)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 22 02:01:15 PST 2025


================
@@ -501,6 +519,110 @@ bool Sema::CheckEquivalentExceptionSpec(
   return Result;
 }
 
+static const Expr *SubstituteExceptionSpecWithoutEvaluation(
+    Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
+    const Expr *ExceptionSpec) {
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+      DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
+      /*Innermost=*/std::nullopt,
+      /*RelativeToPrimary=*/true,
+      /*ForConstraintInstantiation=*/true);
+
+  if (MLTAL.getNumSubstitutedLevels() == 0)
+    return ExceptionSpec;
+
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/false);
+
+  auto *FD = const_cast<FunctionDecl *>(DeclInfo.getDecl()->getAsFunction());
+  Sema::InstantiatingTemplate Inst(
+      S, DeclInfo.getLocation(), FD,
+      Sema::InstantiatingTemplate::ExceptionSpecification());
+  if (Inst.isInvalid())
+    return nullptr;
+
+  // Set up a dummy 'instantiation' scope in the case of reference to function
+  // parameters that the surrounding function hasn't been instantiated yet. Note
+  // this may happen while we're comparing two templates' constraint
+  // equivalence.
+  LocalInstantiationScope ScopeForParameters(S);
+
+  for (auto *PVD : FD->parameters()) {
+    if (!PVD->isParameterPack()) {
+      ScopeForParameters.InstantiatedLocal(PVD, PVD);
+      continue;
+    }
+    // This is hacky: we're mapping the parameter pack to a size-of-1 argument
+    // to avoid building SubstTemplateTypeParmPackTypes for
+    // PackExpansionTypes. The SubstTemplateTypeParmPackType node would
+    // otherwise reference the AssociatedDecl of the template arguments, which
+    // is, in this case, the template declaration.
+    //
+    // However, as we are in the process of comparing potential
+    // re-declarations, the canonical declaration is the declaration itself at
+    // this point. So if we didn't expand these packs, we would end up with an
+    // incorrect profile difference because we will be profiling the
+    // canonical types!
+    //
+    // FIXME: Improve the "no-transform" machinery in FindInstantiatedDecl so
+    // that we can eliminate the Scope in the cases where the declarations are
+    // not necessarily instantiated. It would also benefit the noexcept
+    // specifier comparison.
+    ScopeForParameters.MakeInstantiatedLocalArgPack(PVD);
+    ScopeForParameters.InstantiatedLocalPackArg(PVD, PVD);
+  }
+
+  // See TreeTransform::RebuildTemplateSpecializationType. A context scope is
+  // essential for having an injected class as the canonical type for a template
+  // specialization type at the rebuilding stage. This guarantees that, for
+  // out-of-line definitions, injected class name types and their equivalent
+  // template specializations can be profiled to the same value, which makes it
+  // possible that e.g. constraints involving C<Class<T>> and C<Class> are
+  // perceived identical.
+  Sema::ContextRAII ContextScope(S, FD);
+
+  auto *MD = dyn_cast<CXXMethodDecl>(FD);
+  Sema::CXXThisScopeRAII ThisScope(
+      S, MD ? MD->getParent() : nullptr,
+      MD ? MD->getMethodQualifiers() : Qualifiers{}, MD != nullptr);
+
+  EnterExpressionEvaluationContext ConstantEvaluated(
+      S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
----------------
cor3ntin wrote:

Should that not be be Unevaluated?
https://eel.is/c++draft/expr.unary.noexcept#1

https://github.com/llvm/llvm-project/pull/111561


More information about the cfe-commits mailing list