Tom Honermann 4409a83c29 [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
2022-10-04 09:04:54 -07:00

55 lines
2.1 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -triple i386-windows
void defargs() {
auto l1 = [](int i, int j = 17, int k = 18) { return i + j + k; };
int i1 = l1(1);
int i2 = l1(1, 2);
int i3 = l1(1, 2, 3);
}
void defargs_errors() {
auto l1 = [](int i,
int j = 17,
int k) { }; // expected-error{{missing default argument on parameter 'k'}}
auto l2 = [](int i, int j = i) {}; // expected-error{{default argument references parameter 'i'}}
int foo;
auto l3 = [](int i = foo) {}; // expected-error{{default argument references local variable 'foo' of enclosing function}}
}
struct NonPOD {
NonPOD();
NonPOD(const NonPOD&);
~NonPOD();
};
struct NoDefaultCtor {
NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}} \
// expected-note{{candidate constructor not viable: requires 1 argument, but 0 were provided}}
~NoDefaultCtor();
};
template<typename T>
void defargs_in_template_unused(T t) {
auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
// expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
l1(t);
}
template void defargs_in_template_unused(NonPOD);
template void defargs_in_template_unused(NoDefaultCtor); // expected-note{{in instantiation of function template specialization 'defargs_in_template_unused<NoDefaultCtor>' requested here}}
template<typename T>
void defargs_in_template_used() {
auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
// expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
l1();
}
template void defargs_in_template_used<NonPOD>();
template void defargs_in_template_used<NoDefaultCtor>(); // expected-note{{in instantiation of function template specialization}}