[clang] f721e05 - PR46648: Do not eagerly instantiate default arguments for a generic
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 9 17:24:58 PDT 2020
Author: Richard Smith
Date: 2020-07-09T17:24:20-07:00
New Revision: f721e0582b158c60c56d2601235b6d60758f4d7a
URL: https://github.com/llvm/llvm-project/commit/f721e0582b158c60c56d2601235b6d60758f4d7a
DIFF: https://github.com/llvm/llvm-project/commit/f721e0582b158c60c56d2601235b6d60758f4d7a.diff
LOG: PR46648: Do not eagerly instantiate default arguments for a generic
lambda when instantiating a call operator specialization.
We previously incorrectly thought that such substitution was happening
in the context of substitution into a local scope, which is a context
where we should perform eager default argument instantiation.
Added:
Modified:
clang/include/clang/AST/DeclBase.h
clang/lib/AST/DeclBase.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/SemaTemplate/default-arguments-cxx0x.cpp
clang/test/SemaTemplate/dependent-expr.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 5e00be35d8ce..4f33ff104ffd 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -875,15 +875,19 @@ class alignas(8) Decl {
return getParentFunctionOrMethod() == nullptr;
}
- /// 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 and lambdas:
+ /// Determine whether a substitution into this declaration would occur as
+ /// part of a substitution into a dependent local scope. Such a substitution
+ /// transitively substitutes into all constructs nested within this
+ /// declaration.
+ ///
+ /// This recognizes non-defining declarations as well as members of local
+ /// classes and lambdas:
/// \code
- /// void foo() { void bar(); }
- /// void foo2() { class ABC { void bar(); }; }
- /// inline int x = [](){ return 0; }();
+ /// template<typename T> void foo() { void bar(); }
+ /// template<typename T> void foo2() { class ABC { void bar(); }; }
+ /// template<typename T> inline int x = [](){ return 0; }();
/// \endcode
- bool isInLocalScope() const;
+ bool isInLocalScopeForInstantiation() const;
/// If this decl is defined inside a function/method/block it returns
/// the corresponding DeclContext, otherwise it returns null.
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 3fd27757815e..da1eadd9d931 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -364,8 +364,10 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
}
}
-bool Decl::isInLocalScope() const {
+bool Decl::isInLocalScopeForInstantiation() const {
const DeclContext *LDC = getLexicalDeclContext();
+ if (!LDC->isDependentContext())
+ return false;
while (true) {
if (LDC->isFunctionOrMethod())
return true;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 8197e7d901e9..11e03c517d01 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2426,7 +2426,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->isInLocalScope()) {
+ if (OwningFunc->isInLocalScopeForInstantiation()) {
// Instantiate default arguments for methods of local classes (DR1484)
// and non-defining declarations.
Sema::ContextRAII SavedContext(*this, OwningFunc);
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6179d90d54f7..85adc4ef2dbd 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4458,7 +4458,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpec.Type != EST_None &&
EPI.ExceptionSpec.Type != EST_DynamicNone &&
EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
- !Tmpl->isInLocalScope()) {
+ !Tmpl->isInLocalScopeForInstantiation()) {
FunctionDecl *ExceptionSpecTemplate = Tmpl;
if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
diff --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
index 02696a80bc0f..1aa456553599 100644
--- a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
// expected-no-diagnostics
// Test default template arguments for function templates.
@@ -132,5 +133,32 @@ namespace lambda {
void foo() {
bar<int>();
}
+
+#if __cplusplus >= 202002L
+ // PR46648: ensure we don't reject this by triggering default argument
+ // instantiation spuriously.
+ auto x = []<typename T>(T x = 123) {};
+ void y() { x(nullptr); }
+
+ template<int A> struct X {
+ template<int B> constexpr int f() {
+ auto l = []<int C>(int n = A + B + C) { return n; };
+ return l.template operator()<3>();
+ }
+ };
+ static_assert(X<100>().f<20>() == 123);
+
+ template<> template<int B> constexpr int X<200>::f() {
+ auto l = []<int C>(int n = 300 + B + C) { return n; };
+ return l.template operator()<1>();
+ }
+ static_assert(X<200>().f<20>() == 321);
+
+ template<> template<> constexpr int X<300>::f<20>() {
+ auto l = []<int C>(int n = 450 + C) { return n; };
+ return l.template operator()<6>();
+ }
+ static_assert(X<300>().f<20>() == 456);
+#endif
} // namespace lambda
#endif
diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp
index 0ce4cb39d349..abdb8e9c4a9f 100644
--- a/clang/test/SemaTemplate/dependent-expr.cpp
+++ b/clang/test/SemaTemplate/dependent-expr.cpp
@@ -144,7 +144,7 @@ namespace PR45083 {
void h(auto a, void*) {} // expected-error {{redefinition}}
void i(auto a) {
- [](auto a, int = ({decltype(a) i; i * 2;})){}(a); // expected-error {{no matching function}} expected-note {{substitution failure}}
+ [](auto a, int = ({decltype(a) i; i * 2;})){}(a); // expected-error {{invalid operands to binary expression ('decltype(a)' (aka 'void *') and 'int')}} expected-note {{in instantiation of}}
}
void use_i() {
i(0);
More information about the cfe-commits
mailing list