This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG3784e8ccfbda: [Clang] Fix Unevaluated Lambdas (authored by
cor3ntin).
Changed prior to commit:
https://reviews.llvm.org/D121532?vs=418269&id=418277#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D121532/new/
https://reviews.llvm.org/D121532
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/DeclCXX.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/DeclBase.cpp
clang/lib/AST/DeclCXX.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/SemaCXX/lambda-unevaluated.cpp
clang/unittests/AST/ASTImporterTest.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1024,7 +1024,11 @@
<tr>
<td>Lambdas in unevaluated contexts</td>
<td><a href="https://wg21.link/p0315r4">P0315R4</a></td>
- <td class="partial" align="center">Partial</td>
+ <td class="partial" align="center">
+ <details><summary>Partial</summary>
+ temp.deduct/9 is not implemented yet.
+ </details>
+ </td>
</tr>
<!-- Jacksonville papers -->
<tr>
Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -5824,6 +5824,7 @@
std::distance(FromL->decls().begin(), FromL->decls().end());
EXPECT_NE(ToLSize, 0u);
EXPECT_EQ(ToLSize, FromLSize);
+ EXPECT_FALSE(FromL->isDependentLambda());
}
TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionParam) {
@@ -5843,6 +5844,7 @@
std::distance(FromL->decls().begin(), FromL->decls().end());
EXPECT_NE(ToLSize, 0u);
EXPECT_EQ(ToLSize, FromLSize);
+ EXPECT_TRUE(FromL->isDependentLambda());
}
TEST_P(ASTImporterOptionSpecificTestBase, LambdaInGlobalScope) {
Index: clang/test/SemaCXX/lambda-unevaluated.cpp
===================================================================
--- clang/test/SemaCXX/lambda-unevaluated.cpp
+++ clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -30,6 +30,27 @@
auto e = g(0); // expected-error{{no matching function for call}}
// expected-note@-2 {{substitution failure}}
+template <typename T>
+auto foo(decltype([] {
+ return [] { return T(); }();
+})) {}
+
+void test() {
+ foo<int>({});
+}
+
+template <typename T>
+struct C {
+ template <typename U>
+ auto foo(decltype([] {
+ return [] { return T(); }();
+ })) {}
+};
+
+void test2() {
+ C<int>{}.foo<long>({});
+}
+
namespace PR52073 {
// OK, these are distinct functions not redefinitions.
template<typename> void f(decltype([]{})) {} // expected-note {{candidate}}
@@ -40,6 +61,62 @@
template<int N> void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}}
template<int N> void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}}
// FIXME: We instantiate the lambdas into the context of the function template,
-// so we think they're dependent and can't evaluate a call to them.
+// so we think they're dependent and can't evaluate a call to them.
void use_g() { g<6>(&"hello"); } // expected-error {{no matching function}}
}
+
+namespace GH51416 {
+
+template <class T>
+struct A {
+ void spam(decltype([] {}));
+};
+
+template <class T>
+void A<T>::spam(decltype([] {})) // expected-error{{out-of-line definition of 'spam' does not match}}
+{}
+
+struct B {
+ template <class T>
+ void spam(decltype([] {}));
+};
+
+template <class T>
+void B::spam(decltype([] {})) {} // expected-error{{out-of-line definition of 'spam' does not match}}
+
+} // namespace GH51416
+
+namespace GH50376 {
+
+template <typename T, typename Fn>
+struct foo_t { // expected-note 2{{candidate constructor}}
+ foo_t(T ptr) {} // expected-note{{candidate constructor}}
+};
+
+template <typename T>
+using alias = foo_t<T, decltype([](int) { return 0; })>;
+
+template <typename T>
+auto fun(T const &t) -> alias<T> {
+ return alias<T>{t}; // expected-error{{no viable conversion from returned value of type 'alias<...>'}}
+}
+
+void f() {
+ int i;
+ auto const error = fun(i); // expected-note{{in instantiation}}
+}
+
+} // namespace GH50376
+
+namespace GH51414 {
+template <class T> void spam(decltype([] {}) (*s)[sizeof(T)] = nullptr) {}
+void foo() {
+ spam<int>();
+}
+} // namespace GH51414
+
+namespace GH51641 {
+template <class T>
+void foo(decltype(+[](T) {}) lambda, T param);
+static_assert(!__is_same(decltype(foo<int>), void));
+} // namespace GH51641
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -5733,7 +5733,7 @@
// Add lambda-specific data.
if (Data.IsLambda) {
auto &Lambda = D->getLambdaData();
- Record->push_back(Lambda.Dependent);
+ Record->push_back(Lambda.DependencyKind);
Record->push_back(Lambda.IsGenericLambda);
Record->push_back(Lambda.CaptureDefault);
Record->push_back(Lambda.NumCaptures);
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1801,7 +1801,7 @@
using Capture = LambdaCapture;
auto &Lambda = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
- Lambda.Dependent = Record.readInt();
+ Lambda.DependencyKind = Record.readInt();
Lambda.IsGenericLambda = Record.readInt();
Lambda.CaptureDefault = Record.readInt();
Lambda.NumCaptures = Record.readInt();
@@ -1917,8 +1917,8 @@
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record.readInt();
if (IsLambda)
- DD = new (C) CXXRecordDecl::LambdaDefinitionData(D, nullptr, false, false,
- LCD_None);
+ DD = new (C) CXXRecordDecl::LambdaDefinitionData(
+ D, nullptr, CXXRecordDecl::LDK_Unknown, false, LCD_None);
else
DD = new (C) struct CXXRecordDecl::DefinitionData(D);
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -12982,14 +12982,24 @@
NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
// Create the local class that will describe the lambda.
- // FIXME: KnownDependent below is wrong when substituting inside a templated
- // context that isn't a DeclContext (such as a variable template).
+
+ // FIXME: DependencyKind below is wrong when substituting inside a templated
+ // context that isn't a DeclContext (such as a variable template), or when
+ // substituting an unevaluated lambda inside of a function's parameter's type
+ // - as parameter types are not instantiated from within a function's DC. We
+ // use isUnevaluatedContext() to distinguish the function parameter case.
+ CXXRecordDecl::LambdaDependencyKind DependencyKind =
+ CXXRecordDecl::LDK_Unknown;
+ if (getSema().isUnevaluatedContext() &&
+ (getSema().CurContext->isFileContext() ||
+ !getSema().CurContext->getParent()->isDependentContext()))
+ DependencyKind = CXXRecordDecl::LDK_NeverDependent;
+
CXXRecordDecl *OldClass = E->getLambdaClass();
- CXXRecordDecl *Class
- = getSema().createLambdaClosureType(E->getIntroducerRange(),
- NewCallOpTSI,
- /*KnownDependent=*/false,
- E->getCaptureDefault());
+ CXXRecordDecl *Class =
+ getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI,
+ DependencyKind, E->getCaptureDefault());
+
getDerived().transformedLocalDecl(OldClass, {Class});
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1853,7 +1853,7 @@
if (D->isLambda())
Record = CXXRecordDecl::CreateLambda(
SemaRef.Context, Owner, D->getLambdaTypeInfo(), D->getLocation(),
- D->isDependentLambda(), D->isGenericLambda(),
+ D->getLambdaDependencyKind(), D->isGenericLambda(),
D->getLambdaCaptureDefault());
else
Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -238,21 +238,19 @@
return LSI->GLTemplateParameterList;
}
-CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
- TypeSourceInfo *Info,
- bool KnownDependent,
- LambdaCaptureDefault CaptureDefault) {
+CXXRecordDecl *
+Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info,
+ unsigned LambdaDependencyKind,
+ LambdaCaptureDefault CaptureDefault) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
*this);
// Start constructing the lambda class.
- CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info,
- IntroducerRange.getBegin(),
- KnownDependent,
- IsGenericLambda,
- CaptureDefault);
+ CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(
+ Context, DC, Info, IntroducerRange.getBegin(), LambdaDependencyKind,
+ IsGenericLambda, CaptureDefault);
DC->addDecl(Class);
return Class;
@@ -898,17 +896,18 @@
// Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope.
- bool KnownDependent;
+ CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
+ CXXRecordDecl::LDK_Unknown;
if (LSI->NumExplicitTemplateParams > 0) {
auto *TemplateParamScope = CurScope->getTemplateParamParent();
assert(TemplateParamScope &&
"Lambda with explicit template param list should establish a "
"template param scope");
assert(TemplateParamScope->getParent());
- KnownDependent = TemplateParamScope->getParent()
- ->getTemplateParamParent() != nullptr;
- } else {
- KnownDependent = CurScope->getTemplateParamParent() != nullptr;
+ if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr)
+ LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
+ } else if (CurScope->getTemplateParamParent() != nullptr) {
+ LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
}
// Determine the signature of the call operator.
@@ -977,8 +976,8 @@
UPPC_DeclarationType);
}
- CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
- KnownDependent, Intro.Default);
+ CXXRecordDecl *Class = createLambdaClosureType(
+ Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default);
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -146,16 +146,16 @@
CXXRecordDecl *
CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
- bool Dependent, bool IsGeneric,
+ unsigned DependencyKind, bool IsGeneric,
LambdaCaptureDefault CaptureDefault) {
auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, C, DC, Loc, Loc,
nullptr, nullptr);
R->setBeingDefined(true);
- R->DefinitionData =
- new (C) struct LambdaDefinitionData(R, Info, Dependent, IsGeneric,
- CaptureDefault);
+ R->DefinitionData = new (C) struct LambdaDefinitionData(
+ R, Info, DependencyKind, IsGeneric, CaptureDefault);
R->setMayHaveOutOfDateDef(false);
R->setImplicit(true);
+
C.getTypeDeclType(R, /*PrevDecl=*/nullptr);
return R;
}
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -1161,6 +1161,8 @@
if (Record->isDependentLambda())
return true;
+ if (Record->isNeverDependentLambda())
+ return false;
}
if (const auto *Function = dyn_cast<FunctionDecl>(this)) {
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2874,7 +2874,7 @@
return TInfoOrErr.takeError();
if (GetImportedOrCreateSpecialDecl(
D2CXX, CXXRecordDecl::CreateLambda, D, Importer.getToContext(),
- DC, *TInfoOrErr, Loc, DCXX->isDependentLambda(),
+ DC, *TInfoOrErr, Loc, DCXX->getLambdaDependencyKind(),
DCXX->isGenericLambda(), DCXX->getLambdaCaptureDefault()))
return D2CXX;
ExpectedDecl CDeclOrErr = import(DCXX->getLambdaContextDecl());
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6783,7 +6783,7 @@
/// Create a new lambda closure type.
CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
TypeSourceInfo *Info,
- bool KnownDependent,
+ unsigned LambdaDependencyKind,
LambdaCaptureDefault CaptureDefault);
/// Start the definition of a lambda expression.
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -275,6 +275,14 @@
SMF_All = 0x3f
};
+public:
+ enum LambdaDependencyKind {
+ LDK_Unknown = 0,
+ LDK_AlwaysDependent,
+ LDK_NeverDependent,
+ };
+
+private:
struct DefinitionData {
#define FIELD(Name, Width, Merge) \
unsigned Name : Width;
@@ -374,7 +382,7 @@
/// lambda will have been created with the enclosing context as its
/// declaration context, rather than function. This is an unfortunate
/// artifact of having to parse the default arguments before.
- unsigned Dependent : 1;
+ unsigned DependencyKind : 2;
/// Whether this lambda is a generic lambda.
unsigned IsGenericLambda : 1;
@@ -408,9 +416,9 @@
/// The type of the call method.
TypeSourceInfo *MethodTyInfo;
- LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent,
+ LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, unsigned DK,
bool IsGeneric, LambdaCaptureDefault CaptureDefault)
- : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric),
+ : DefinitionData(D), DependencyKind(DK), IsGenericLambda(IsGeneric),
CaptureDefault(CaptureDefault), NumCaptures(0),
NumExplicitCaptures(0), HasKnownInternalLinkage(0), ManglingNumber(0),
MethodTyInfo(Info) {
@@ -547,7 +555,7 @@
bool DelayTypeCreation = false);
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
- bool DependentLambda, bool IsGeneric,
+ unsigned DependencyKind, bool IsGeneric,
LambdaCaptureDefault CaptureDefault);
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
@@ -1774,7 +1782,17 @@
/// function declaration itself is dependent. This flag indicates when we
/// know that the lambda is dependent despite that.
bool isDependentLambda() const {
- return isLambda() && getLambdaData().Dependent;
+ return isLambda() && getLambdaData().DependencyKind == LDK_AlwaysDependent;
+ }
+
+ bool isNeverDependentLambda() const {
+ return isLambda() && getLambdaData().DependencyKind == LDK_NeverDependent;
+ }
+
+ unsigned getLambdaDependencyKind() const {
+ if (!isLambda())
+ return LDK_Unknown;
+ return getLambdaData().DependencyKind;
}
TypeSourceInfo *getLambdaTypeInfo() const {
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -83,6 +83,14 @@
per identifier.
Fixes `Issue 28985 <https://github.com/llvm/llvm-project/issues/28985>`_.
+- Unevaluated lambdas in dependant contexts no longer result in clang crashing.
+ This fixes Issues `50376 < https://github.com/llvm/llvm-project/issues/50376>`_,
+ `54296 < https://github.com/llvm/llvm-project/issues/54296>`_,
+ `51414 < https://github.com/llvm/llvm-project/issues/51414>`_,
+ `51416 < https://github.com/llvm/llvm-project/issues/51416>`_,
+ and `51641 < https://github.com/llvm/llvm-project/issues/51641>`_.
+
+
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``-Wliteral-range`` will warn on floating-point equality comparisons with
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits