[clang] 90fce46 - Fix crash-on-invalid-code in lambda constant evaluation.

James Y Knight via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 4 12:12:23 PST 2019


Author: James Y Knight
Date: 2019-12-04T15:12:17-05:00
New Revision: 90fce46fa6c9ccec86f642be0a75da2d0a5b11c1

URL: https://github.com/llvm/llvm-project/commit/90fce46fa6c9ccec86f642be0a75da2d0a5b11c1
DIFF: https://github.com/llvm/llvm-project/commit/90fce46fa6c9ccec86f642be0a75da2d0a5b11c1.diff

LOG: Fix crash-on-invalid-code in lambda constant evaluation.

If the lambda used 'this' without without capturing it, an error was
emitted, but the constant evaluator would still attempt to lookup the
capture, and failing to find it, dereference a null pointer.

This only happens in C++17 (as that's when lambdas were made
potentially-constexpr). Therefore, I also updated the
lambda-expressions.cpp test to run in both C++14 and C++17 modes.

Added: 
    

Modified: 
    clang/lib/AST/ExprConstant.cpp
    clang/test/SemaCXX/lambda-expressions.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index df80cb4f9440..7a17b76f05d3 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -7861,6 +7861,11 @@ class PointerExprEvaluator
     // either copied into the closure object's field that represents the '*this'
     // or refers to '*this'.
     if (isLambdaCallOperator(Info.CurrentCall->Callee)) {
+      // Ensure we actually have captured 'this'. (an error will have
+      // been previously reported if not).
+      if (!Info.CurrentCall->LambdaThisCaptureField)
+        return false;
+
       // Update 'Result' to refer to the data member/field of the closure object
       // that represents the '*this' capture.
       if (!HandleLValueMember(Info, E, Result,

diff  --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index 5fff855102fb..0f4edc4d1f34 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -fblocks %s
+// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -verify=expected-cxx14 -fblocks %s
+// RUN: %clang_cc1 -std=c++17 -Wno-unused-value -fsyntax-only -verify -fblocks %s
 
 namespace std { class type_info; };
 
@@ -12,6 +13,7 @@ namespace ExplicitCapture {
 
     void ImplicitThisCapture() {
       [](){(void)Member;}; // expected-error {{'this' cannot be implicitly captured in this context}}
+      const int var = [](){(void)Member; return 0;}(); // expected-error {{'this' cannot be implicitly captured in this context}}
       [&](){(void)Member;};
 
       [this](){(void)Member;};
@@ -105,7 +107,7 @@ namespace SpecialMembers {
     a = static_cast<decltype(a)&&>(a); // expected-error {{copy assignment operator is implicitly deleted}}
   }
   struct P {
-    P(const P&) = delete; // expected-note 2{{deleted here}}
+    P(const P&) = delete; //expected-note {{deleted here}} // expected-cxx14-note {{deleted here}}
   };
   struct Q {
     ~Q() = delete; // expected-note {{deleted here}}
@@ -118,8 +120,8 @@ namespace SpecialMembers {
   };
   void g(P &p, Q &q, R &r) {
     // FIXME: The note attached to the second error here is just amazingly bad.
-    auto pp = [p]{}; // expected-error {{deleted constructor}} expected-error {{deleted copy constructor of '(lambda}}
-    // expected-note at -1 {{copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor}}
+    auto pp = [p]{}; // expected-error {{deleted constructor}} expected-cxx14-error {{deleted copy constructor of '(lambda}}
+    // expected-cxx14-note at -1 {{copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor}}
     auto qq = [q]{}; // expected-error {{deleted function}} expected-note {{because}}
 
     auto a = [r]{}; // expected-note 2{{here}}
@@ -365,7 +367,7 @@ namespace PR18128 {
     int (*f())[true ? 1 : ([=]{ return n; }(), 0)];
     // expected-error at -1 {{non-local lambda expression cannot have a capture-default}}
     // expected-error at -2 {{invalid use of non-static data member 'n'}}
-    // expected-error at -3 {{a lambda expression may not appear inside of a constant expression}}
+    // expected-cxx14-error at -3 {{a lambda expression may not appear inside of a constant expression}}
     int g(int k = ([=]{ return n; }(), 0));
     // expected-error at -1 {{non-local lambda expression cannot have a capture-default}}
     // expected-error at -2 {{invalid use of non-static data member 'n'}}
@@ -596,8 +598,13 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
     using ExpectedTypeU = void (*)(T&);
 
   struct X {
+#if __cplusplus > 201402L
+    friend constexpr auto T::operator()(int) const;
+    friend constexpr T::operator ExpectedTypeT() const noexcept;
+#else
     friend auto T::operator()(int) const;
     friend T::operator ExpectedTypeT() const;
+#endif
 
     // FIXME: The first of these should match. The second should not.
     template<typename T>


        


More information about the cfe-commits mailing list