================ @@ -313,9 +313,75 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec, // This is to make sure we pick up the VarTemplateSpecializationDecl that this // lambda is defined inside of. - if (Rec->isLambda()) + if (Rec->isLambda()) { if (const Decl *LCD = Rec->getLambdaContextDecl()) return Response::ChangeDecl(LCD); + // Attempt to retrieve the template arguments for a using alias declaration. + // This is necessary for constraint checking, since we always keep + // constraints relative to the primary template. + if (ForConstraintInstantiation && !SemaRef.CodeSynthesisContexts.empty()) { + for (auto &CSC : llvm::reverse(SemaRef.CodeSynthesisContexts)) { + if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind:: + TypeAliasTemplateInstantiation) + continue; + auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity), + *CurrentTATD = TATD; + FunctionDecl *LambdaCallOperator = Rec->getLambdaCallOperator(); + // Retrieve the 'primary' template for a lambda call operator. It's + // unfortunate that we only have the mappings of call operators rather + // than lambda classes. + while (true) { + auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>( + LambdaCallOperator->getDescribedTemplate()); + if (FTD && FTD->getInstantiatedFromMemberTemplate()) { + LambdaCallOperator = + FTD->getInstantiatedFromMemberTemplate()->getTemplatedDecl(); + } else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator) + ->getInstantiatedFromMemberFunction()) + LambdaCallOperator = Prev; + else + break; + } + // Same applies for type alias Decl. We perform this to obtain the + // "canonical" template parameter depths. + while (TATD->getInstantiatedFromMemberTemplate()) + TATD = TATD->getInstantiatedFromMemberTemplate(); + // Tell if we're currently inside of a lambda expression that is + // surrounded by a using alias declaration. e.g. + // template <class> using type = decltype([](auto) { ^ }()); + // By checking if: + // 1. The lambda expression and the using alias declaration share the + // same declaration context. + // 2. They have the same template depth. + // Then we assume the template arguments from the using alias + // declaration are essential for constraint instantiation. We have to do + // so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never a + // DeclContext, nor does it have an associated specialization Decl from + // which we could collect these template arguments. + if (cast<CXXRecordDecl>(LambdaCallOperator->getDeclContext()) + ->getTemplateDepth() == TATD->getTemplateDepth() && + getLambdaAwareParentOfDeclContext(LambdaCallOperator) == + TATD->getDeclContext()) { + Result.addOuterTemplateArguments(CurrentTATD, + CSC.template_arguments(), + /*Final=*/false); + // Visit the parent of the current type alias declaration rather than + // the lambda thereof. We have the following case: ---------------- cor3ntin wrote:
```suggestion // Visit the parent of the current type alias declaration rather than // the lambda thereof. E.g, in the following example: ``` https://github.com/llvm/llvm-project/pull/82310 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits