#include "CPlusPlusNameParser.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Threading.h"
Bookmark start_position = SetBookmark();
if (expect_return_type) {
// Consume return type if it's expected.
- if (!ConsumeTypename())
+ if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
return None;
}
--- /dev/null
+CXX_SOURCES := main.cpp
+CXXFLAGS_EXTRAS := -std=c++20
+
+include Makefile.rules
--- /dev/null
+"""
+Test thread step-in ignores frames according to the "Avoid regexp" option.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class StepAvoidsRegexTestCase(TestBase):
+ def hit_correct_function(self, pattern):
+ name = self.thread.frames[0].GetFunctionName()
+ self.assertTrue(
+ pattern in name, "Got to '%s' not the expected function '%s'." %
+ (name, pattern))
+
+ def setUp(self):
+ TestBase.setUp(self)
+ self.dbg.HandleCommand(
+ "settings set target.process.thread.step-avoid-regexp ^ignore::")
+
+ def test_step_avoid_regex(self):
+ """Tests stepping into a function which matches the avoid regex"""
+ self.build()
+ (_, _, self.thread, _) = lldbutil.run_to_source_breakpoint(self, "main", lldb.SBFileSpec('main.cpp'))
+
+ # Try to step into ignore::auto_ret
+ self.thread.StepInto()
+ self.hit_correct_function("main")
+
+ # Try to step into ignore::with_tag
+ self.thread.StepInto()
+ self.hit_correct_function("main")
+
+ # Try to step into ignore::decltype_auto_ret
+ self.thread.StepInto()
+ self.hit_correct_function("main")
+
+ @expectedFailureAll(bugnumber="rdar://100645742")
+ def test_step_avoid_regex_abi_tagged_template(self):
+ """Tests stepping into an ABI tagged function that matches the avoid regex"""
+ self.build()
+ (_, _, self.thread, _) = lldbutil.run_to_source_breakpoint(self, "with_tag_template", lldb.SBFileSpec('main.cpp'))
+
+ # Try to step into ignore::with_tag_template
+ self.thread.StepInto()
+ self.hit_correct_function("main")
--- /dev/null
+namespace ignore {
+template <typename T> auto auto_ret(T x) { return 0; }
+[[gnu::abi_tag("test")]] int with_tag() { return 0; }
+template <typename T> [[gnu::abi_tag("test")]] int with_tag_template() {
+ return 0;
+}
+
+template <typename T> decltype(auto) decltype_auto_ret(T x) { return 0; }
+} // namespace ignore
+
+int main() {
+ auto v1 = ignore::auto_ret<int>(5);
+ auto v2 = ignore::with_tag();
+ auto v3 = ignore::decltype_auto_ret<int>(5);
+ auto v4 = ignore::with_tag_template<int>();
+}
"XX::(anonymous namespace)::anon_class::anon_func"},
// Lambda
- {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const",
- "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()", "()", "const",
+ {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() "
+ "const",
+ "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
+ "()", "const",
"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
// Function pointers
"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"},
{"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&",
- "llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const volatile &&",
- "llvm::Optional<llvm::MCFixupKind>::operator*"}};
+ "llvm::Optional<llvm::MCFixupKind>", "operator*", "()",
+ "const volatile &&", "llvm::Optional<llvm::MCFixupKind>::operator*"},
+
+ // auto return type
+ {"auto std::test_return_auto<int>() const", "std",
+ "test_return_auto<int>", "()", "const", "std::test_return_auto<int>"},
+ {"decltype(auto) std::test_return_auto<int>(int) const", "std",
+ "test_return_auto<int>", "(int)", "const",
+ "std::test_return_auto<int>"}};
for (const auto &test : test_cases) {
CPlusPlusLanguage::MethodName method(ConstString(test.input));