forked from OSchip/llvm-project
PR45000: Let Sema::SubstParmVarDecl handle default args of lambdas in initializers
Summary: We extend the behavior for local functions and methods of local classes to lambdas in variable initializers. The initializer is not a separate scope, but we treat it as such. We also remove the (faulty) instantiation of default arguments in TreeTransform::TransformLambdaExpr, because it doesn't do proper initialization, and if it did, we would do it twice (and thus also emit eventual errors twice). Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D76038
This commit is contained in:
parent
e5291c4ae3
commit
f43859a099
|
@ -869,14 +869,15 @@ public:
|
|||
return getParentFunctionOrMethod() == nullptr;
|
||||
}
|
||||
|
||||
/// Returns true if this declaration lexically is inside a function.
|
||||
/// It recognizes non-defining declarations as well as members of local
|
||||
/// classes:
|
||||
/// Returns true if this declaration is lexically inside a function or inside
|
||||
/// a variable initializer. It recognizes non-defining declarations as well
|
||||
/// as members of local classes:
|
||||
/// \code
|
||||
/// void foo() { void bar(); }
|
||||
/// void foo2() { class ABC { void bar(); }; }
|
||||
/// inline int x = [](){ return 0; };
|
||||
/// \endcode
|
||||
bool isLexicallyWithinFunctionOrMethod() const;
|
||||
bool isInLocalScope() const;
|
||||
|
||||
/// If this decl is defined inside a function/method/block it returns
|
||||
/// the corresponding DeclContext, otherwise it returns null.
|
||||
|
|
|
@ -332,13 +332,16 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
|||
}
|
||||
}
|
||||
|
||||
bool Decl::isLexicallyWithinFunctionOrMethod() const {
|
||||
bool Decl::isInLocalScope() const {
|
||||
const DeclContext *LDC = getLexicalDeclContext();
|
||||
while (true) {
|
||||
if (LDC->isFunctionOrMethod())
|
||||
return true;
|
||||
if (!isa<TagDecl>(LDC))
|
||||
return false;
|
||||
if (const auto *CRD = dyn_cast<CXXRecordDecl>(LDC))
|
||||
if (CRD->isLambda())
|
||||
return true;
|
||||
LDC = LDC->getLexicalParent();
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -2380,7 +2380,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
|||
UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
|
||||
} else if (Expr *Arg = OldParm->getDefaultArg()) {
|
||||
FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
|
||||
if (OwningFunc->isLexicallyWithinFunctionOrMethod()) {
|
||||
if (OwningFunc->isInLocalScope()) {
|
||||
// Instantiate default arguments for methods of local classes (DR1484)
|
||||
// and non-defining declarations.
|
||||
Sema::ContextRAII SavedContext(*this, OwningFunc);
|
||||
|
|
|
@ -4363,7 +4363,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
|
|||
EPI.ExceptionSpec.Type != EST_None &&
|
||||
EPI.ExceptionSpec.Type != EST_DynamicNone &&
|
||||
EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
|
||||
!Tmpl->isLexicallyWithinFunctionOrMethod()) {
|
||||
!Tmpl->isInLocalScope()) {
|
||||
FunctionDecl *ExceptionSpecTemplate = Tmpl;
|
||||
if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
|
||||
ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
|
||||
|
|
|
@ -12219,19 +12219,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
|
||||
LSI->CallOperator = NewCallOperator;
|
||||
|
||||
for (unsigned I = 0, NumParams = NewCallOperator->getNumParams();
|
||||
I != NumParams; ++I) {
|
||||
auto *P = NewCallOperator->getParamDecl(I);
|
||||
if (P->hasUninstantiatedDefaultArg()) {
|
||||
EnterExpressionEvaluationContext Eval(
|
||||
getSema(),
|
||||
Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P);
|
||||
ExprResult R = getDerived().TransformExpr(
|
||||
E->getCallOperator()->getParamDecl(I)->getDefaultArg());
|
||||
P->setDefaultArg(R.get());
|
||||
}
|
||||
}
|
||||
|
||||
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
|
||||
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
|
||||
|
||||
|
|
|
@ -4,7 +4,12 @@ template <class> auto fn0 = [] {};
|
|||
template <typename> void foo0() { fn0<char>(); }
|
||||
|
||||
template<typename T> auto fn1 = [](auto a) { return a + T(1); };
|
||||
template<typename T> auto v1 = [](int a = T(1)) { return a; }();
|
||||
template<typename T> auto v1 = [](int a = T()) { return a; }();
|
||||
// expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
|
||||
// expected-error@-2{{no matching function for call}}
|
||||
// expected-note@-3{{passing argument to parameter 'a' here}}
|
||||
// expected-note@-4{{candidate function not viable}}
|
||||
// expected-note@-5{{conversion candidate of type 'int (*)(int)'}}
|
||||
|
||||
struct S {
|
||||
template<class T>
|
||||
|
@ -16,6 +21,7 @@ int foo2() {
|
|||
X a = 0x61;
|
||||
fn1<char>(a);
|
||||
(void)v1<int>;
|
||||
(void)v1<int *>; // expected-note{{in instantiation of variable template specialization 'v1' requested here}}
|
||||
(void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -486,3 +486,16 @@ namespace anon_union_default_member_init {
|
|||
}
|
||||
void g() { f<int>(); }
|
||||
}
|
||||
|
||||
namespace PR45000 {
|
||||
template <typename T>
|
||||
void f(int x = [](T x = nullptr) -> int { return x; }());
|
||||
// expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'nullptr_t'}}
|
||||
// expected-note@-2 {{passing argument to parameter 'x' here}}
|
||||
// expected-error@-3 {{no matching function for call}}
|
||||
// expected-note@-4 {{candidate function not viable: requires single argument 'x', but no arguments were provided}}
|
||||
// expected-note@-5 {{conversion candidate of type 'auto (*)(int) -> int'}}
|
||||
|
||||
void g() { f<int>(); }
|
||||
// expected-note@-1 {{in instantiation of default function argument expression for 'f<int>' required here}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue