[clang] Correct handling of lambdas in lambda default arguments in dependent contexts.
authorTom Honermann <tom.honermann@intel.com>
Fri, 6 May 2022 20:55:05 +0000 (13:55 -0700)
committerTom Honermann <tom.honermann@intel.com>
Tue, 4 Oct 2022 16:04:54 +0000 (09:04 -0700)
commit4409a83c293537e22da046b54e9f69454cdd3dca
tree7b57b2f7a90ce976076b0f6c77ad7fdf30dd5a71
parent0a1210e482c7d8bd8d4bf1740a5175b29d05da17
[clang] Correct handling of lambdas in lambda default arguments in dependent contexts.

Previously, a lambda expression in a dependent context with a default argument
containing an immediately invoked lambda expression would produce a closure
class object that, if invoked such that the default argument was used, resulted
in a compiler crash or one of the following assertion failures during code
generation. The failures occurred regardless of whether the lambda expressions
were dependent.

  clang/lib/CodeGen/CGCall.cpp:
  Assertion `(isGenericMethod || Ty->isVariablyModifiedType() || Ty.getNonReferenceType()->isObjCRetainableType() || getContext() .getCanonicalType(Ty.getNonReferenceType()) .getTypePtr() == getContext().getCanonicalType((*Arg)->getType()).getTypePtr()) && "type mismatch in call argument!"' failed.

  clang/lib/AST/Decl.cpp:
  Assertion `!Init->isValueDependent()' failed.

Default arguments in declarations in local context are instantiated along with
their enclosing function or variable template (since such declarations can't
be explicitly specialized). Previously, such instantiations were performed at
the same time that their associated parameters were instantiated. However, that
approach fails in cases like the following in which the context for the inner
lambda is the outer lambda, but construction of the outer lambda is dependent
on the parameters of the inner lambda. This change resolves this dependency by
delyaing instantiation of default arguments in local contexts until after
construction of the enclosing context.
  template <typename T>
  auto f() {
    return [](T = []{ return T{}; }()) { return 0; };
  }

Refactoring included with this change results in the same code now being used
to instantiate default arguments that appear in local context and those that
are only instantiated when used at a call site; previously, such code was
duplicated and out of sync.

Fixes https://github.com/llvm/llvm-project/issues/49178

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D133500
clang/include/clang/Sema/Sema.h
clang/lib/AST/DeclBase.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
clang/test/CodeGenCXX/mangle-lambdas-cxx14.cpp [new file with mode: 0644]
clang/test/CodeGenCXX/mangle-lambdas-cxx20.cpp [new file with mode: 0644]
clang/test/CodeGenCXX/mangle-lambdas.cpp
clang/test/SemaCXX/vartemplate-lambda.cpp
clang/test/SemaTemplate/default-arguments.cpp
clang/test/SemaTemplate/instantiate-local-class.cpp