This revision was automatically updated to reflect the committed changes.
teemperor marked an inline comment as done.
Closed by commit rG00764c36edf8: [lldb] Add support for evaluating expressions 
in static member functions (authored by teemperor).
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Changed prior to commit:
  https://reviews.llvm.org/D81550?vs=269792&id=339546#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81550/new/

https://reviews.llvm.org/D81550

Files:
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
  lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile
  
lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py
  lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp

Index: lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp
@@ -0,0 +1,31 @@
+struct A {
+  int member_var = 1;
+  static int static_member_var;
+  static const int static_const_member_var;
+  static constexpr int static_constexpr_member_var = 4;
+  int member_func() { return 5; }
+  static int static_func() { return 6; }
+
+  static int context_static_func() {
+    int i = static_member_var;
+    i += static_func();
+    return i; // break in static member function
+  }
+
+  int context_member_func() {
+    int i = member_var;
+    i += member_func();
+    return i; // break in member function
+  }
+};
+
+int A::static_member_var = 2;
+const int A::static_const_member_var = 3;
+constexpr int A::static_constexpr_member_var;
+
+int main() {
+  int i = A::context_static_func();
+  A a;
+  a.context_member_func();
+  return i;
+}
Index: lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py
@@ -0,0 +1,38 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// break in static member function", lldb.SBFileSpec("main.cpp"))
+
+        # Evaluate a static member and call a static member function.
+        self.expect_expr("static_member_var", result_type="int", result_value="2")
+        self.expect_expr("static_const_member_var", result_type="const int", result_value="3")
+        self.expect_expr("static_constexpr_member_var", result_type="const int", result_value="4")
+        self.expect_expr("static_func()", result_type="int", result_value="6")
+
+        # Check that accessing non-static members just reports a diagnostic.
+        self.expect("expr member_var", error=True,
+                    substrs=["invalid use of member 'member_var' in static member function"])
+        self.expect("expr member_func()", error=True,
+                    substrs=["call to non-static member function without an object argument"])
+        self.expect("expr this", error=True,
+                    substrs=["invalid use of 'this' outside of a non-static member function"])
+
+        # Continue to a non-static member function of the same class and make
+        # sure that evaluating non-static members now works.
+        breakpoint = self.target().BreakpointCreateBySourceRegex(
+            "// break in member function", lldb.SBFileSpec("main.cpp"))
+        self.assertNotEqual(breakpoint.GetNumResolvedLocations(), 0)
+        stopped_threads = lldbutil.continue_to_breakpoint(self.process(), breakpoint)
+
+        self.expect_expr("member_var", result_type="int", result_value="1")
+        self.expect_expr("member_func()", result_type="int", result_value="5")
Index: lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -254,7 +254,7 @@
   bool m_in_objectivec_method = false;
   /// True if the expression is compiled as a static (or class) method
   /// (currently true if it was parsed when exe_ctx was in an Objective-C class
-  /// method).
+  /// method or static C++ member function).
   bool m_in_static_method = false;
   /// True if "this" or "self" must be looked up and passed in.  False if the
   /// expression doesn't really use them and they can be NULL.
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -155,32 +155,35 @@
     m_needs_object_ptr = true;
   } else if (clang::CXXMethodDecl *method_decl =
           TypeSystemClang::DeclContextGetAsCXXMethodDecl(decl_context)) {
-    if (m_allow_cxx && method_decl->isInstance()) {
-      if (m_enforce_valid_object) {
-        lldb::VariableListSP variable_list_sp(
-            function_block->GetBlockVariableList(true));
+    if (m_allow_cxx) {
+      if (method_decl->isInstance()) {
+        if (m_enforce_valid_object) {
+          lldb::VariableListSP variable_list_sp(
+              function_block->GetBlockVariableList(true));
 
-        const char *thisErrorString = "Stopped in a C++ method, but 'this' "
-                                      "isn't available; pretending we are in a "
-                                      "generic context";
+          const char *thisErrorString =
+              "Stopped in a C++ method, but 'this' "
+              "isn't available; pretending we are in a "
+              "generic context";
 
-        if (!variable_list_sp) {
-          err.SetErrorString(thisErrorString);
-          return;
-        }
+          if (!variable_list_sp) {
+            err.SetErrorString(thisErrorString);
+            return;
+          }
 
-        lldb::VariableSP this_var_sp(
-            variable_list_sp->FindVariable(ConstString("this")));
+          lldb::VariableSP this_var_sp(
+              variable_list_sp->FindVariable(ConstString("this")));
 
-        if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
-            !this_var_sp->LocationIsValidForFrame(frame)) {
-          err.SetErrorString(thisErrorString);
-          return;
+          if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
+              !this_var_sp->LocationIsValidForFrame(frame)) {
+            err.SetErrorString(thisErrorString);
+            return;
+          }
         }
+        m_needs_object_ptr = true;
       }
-
       m_in_cplusplus_method = true;
-      m_needs_object_ptr = true;
+      m_in_static_method = !method_decl->isInstance();
     }
   } else if (clang::ObjCMethodDecl *method_decl =
                  TypeSystemClang::DeclContextGetAsObjCMethodDecl(
@@ -401,9 +404,11 @@
   assert(m_options.GetExecutionPolicy() != eExecutionPolicyTopLevel &&
          "Top level expressions aren't wrapped.");
   using Kind = ClangExpressionSourceCode::WrapKind;
-  if (m_in_cplusplus_method)
+  if (m_in_cplusplus_method) {
+    if (m_in_static_method)
+      return Kind::CppStaticMemberFunction;
     return Kind::CppMemberFunction;
-  else if (m_in_objectivec_method) {
+  } else if (m_in_objectivec_method) {
     if (m_in_static_method)
       return Kind::ObjCStaticMethod;
     return Kind::ObjCInstanceMethod;
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
@@ -33,12 +33,13 @@
   enum class WrapKind {
     /// Wrapped in a non-static member function of a C++ class.
     CppMemberFunction,
+    /// Wrapped in a static member function of a C++ class.
+    CppStaticMemberFunction,
     /// Wrapped in an instance Objective-C method.
     ObjCInstanceMethod,
     /// Wrapped in a static Objective-C method.
     ObjCStaticMethod,
     /// Wrapped in a non-member function.
-    /// Note that this is also used for static member functions of a C++ class.
     Function
   };
 
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -419,6 +419,7 @@
                          module_imports.c_str(), m_name.c_str(),
                          lldb_local_var_decls.GetData(), tagged_body.c_str());
       break;
+    case WrapKind::CppStaticMemberFunction:
     case WrapKind::CppMemberFunction:
       wrap_stream.Printf("%s"
                          "void                                   \n"
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -608,8 +608,13 @@
   ///
   /// \param[in] type
   ///     The type of the class that serves as the evaluation context.
-  void AddContextClassType(NameSearchContext &context,
-                           const TypeFromUser &type);
+  ///
+  /// \param[in] context_method
+  ///     The member function declaration in which the expression is being
+  ///     evaluated or null if the expression is not evaluated in the context
+  ///     of a member function.
+  void AddContextClassType(NameSearchContext &context, const TypeFromUser &type,
+                           clang::CXXMethodDecl *context_method = nullptr);
 
   /// Move a type out of the current ASTContext into another, but make sure to
   /// export all components of the type also.
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -810,7 +810,7 @@
     LLDB_LOG(log, "  CEDM::FEVD Adding type for $__lldb_class: {1}",
              class_qual_type.getAsString());
 
-    AddContextClassType(context, class_user_type);
+    AddContextClassType(context, class_user_type, method_decl);
 
     if (method_decl->isInstance()) {
       // self is a pointer to the object
@@ -1889,8 +1889,9 @@
   }
 }
 
-void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
-                                                 const TypeFromUser &ut) {
+void ClangExpressionDeclMap::AddContextClassType(
+    NameSearchContext &context, const TypeFromUser &ut,
+    CXXMethodDecl *context_method) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
@@ -1912,7 +1913,12 @@
         void_clang_type, &void_ptr_clang_type, 1, false, 0);
 
     const bool is_virtual = false;
-    const bool is_static = false;
+    // If we evaluate an expression inside a static method, we also need to
+    // make our lldb_expr method static so that Clang denies access to
+    // non-static members.
+    // If we don't have a context_method we are evaluating within a context
+    // object and we can allow access to non-static members.
+    const bool is_static = context_method ? context_method->isStatic() : false;
     const bool is_inline = false;
     const bool is_explicit = false;
     const bool is_attr_used = true;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D8... Raphael Isemann via Phabricator via lldb-commits

Reply via email to