Skip to content

[lldb] upgrade HandleFrameFormatVariable callees to llvm::Expected #144731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

charles-zablit
Copy link
Contributor

Upgrade the callees of HandleFrameFormatVariable (GetDemangledTemplateArguments, etc), to return a llvm::Expected instead of an std::optional.

This patch also bundles the logic of validating the demangled name and information into a single reusable function to reduce code duplication.

@llvmbot
Copy link
Member

llvmbot commented Jun 18, 2025

@llvm/pr-subscribers-lldb

Author: Charles Zablit (charles-zablit)

Changes

Upgrade the callees of HandleFrameFormatVariable (GetDemangledTemplateArguments, etc), to return a llvm::Expected instead of an std::optional.

This patch also bundles the logic of validating the demangled name and information into a single reusable function to reduce code duplication.


Full diff: https://github.com/llvm/llvm-project/pull/144731.diff

1 Files Affected:

  • (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+110-156)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 0f18abb47591d..1810c07652a2b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -236,199 +236,140 @@ static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
   return true;
 }
 
-static std::optional<llvm::StringRef>
-GetDemangledBasename(const SymbolContext &sc) {
+static llvm::Expected<std::pair<llvm::StringRef, DemangledNameInfo>>
+GetAndValidateInfo(const SymbolContext &sc) {
   Mangled mangled = sc.GetPossiblyInlinedFunctionName();
   if (!mangled)
-    return std::nullopt;
+    return llvm::createStringError("Function does not have a mangled name.");
 
   auto demangled_name = mangled.GetDemangledName().GetStringRef();
   if (demangled_name.empty())
-    return std::nullopt;
+    return llvm::createStringError("Function does not have a demangled name.");
 
   const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
   if (!info)
-    return std::nullopt;
+    return llvm::createStringError("Function does not have demangled info.");
 
   // Function without a basename is nonsense.
   if (!info->hasBasename())
-    return std::nullopt;
+    return llvm::createStringError("Info do not have basename range.");
 
-  return demangled_name.slice(info->BasenameRange.first,
-                              info->BasenameRange.second);
+  return std::make_pair(demangled_name, *info);
 }
 
-static std::optional<llvm::StringRef>
-GetDemangledTemplateArguments(const SymbolContext &sc) {
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return std::nullopt;
+static llvm::Expected<llvm::StringRef>
+GetDemangledBasename(const SymbolContext &sc) {
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
 
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return std::nullopt;
+  auto [demangled_name, info] = *info_or_err;
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return std::nullopt;
+  return demangled_name.slice(info.BasenameRange.first,
+                              info.BasenameRange.second);
+}
 
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
-    return std::nullopt;
+static llvm::Expected<llvm::StringRef>
+GetDemangledTemplateArguments(const SymbolContext &sc) {
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
+
+  auto [demangled_name, info] = *info_or_err;
 
-  if (info->ArgumentsRange.first < info->BasenameRange.second)
-    return std::nullopt;
+  if (info.ArgumentsRange.first < info.BasenameRange.second)
+    return llvm::createStringError("Arguments in info are invalid.");
 
-  return demangled_name.slice(info->BasenameRange.second,
-                              info->ArgumentsRange.first);
+  return demangled_name.slice(info.BasenameRange.second,
+                              info.ArgumentsRange.first);
 }
 
-static std::optional<llvm::StringRef>
+static llvm::Expected<llvm::StringRef>
 GetDemangledReturnTypeLHS(const SymbolContext &sc) {
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return std::nullopt;
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
 
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return std::nullopt;
+  auto [demangled_name, info] = *info_or_err;
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return std::nullopt;
+  if (info.ScopeRange.first >= demangled_name.size())
+    return llvm::createStringError("Scope range is invalid.");
 
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
-    return std::nullopt;
-
-  if (info->ScopeRange.first >= demangled_name.size())
-    return std::nullopt;
-
-  return demangled_name.substr(0, info->ScopeRange.first);
+  return demangled_name.substr(0, info.ScopeRange.first);
 }
 
-static std::optional<llvm::StringRef>
+static llvm::Expected<llvm::StringRef>
 GetDemangledFunctionQualifiers(const SymbolContext &sc) {
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return std::nullopt;
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
 
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return std::nullopt;
+  auto [demangled_name, info] = *info_or_err;
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return std::nullopt;
-
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
-    return std::nullopt;
+  if (info.QualifiersRange.second < info.QualifiersRange.first)
+    return llvm::createStringError("Qualifiers range is invalid.");
 
-  if (info->QualifiersRange.second < info->QualifiersRange.first)
-    return std::nullopt;
-
-  return demangled_name.slice(info->QualifiersRange.first,
-                              info->QualifiersRange.second);
+  return demangled_name.slice(info.QualifiersRange.first,
+                              info.QualifiersRange.second);
 }
 
-static std::optional<llvm::StringRef>
+static llvm::Expected<llvm::StringRef>
 GetDemangledReturnTypeRHS(const SymbolContext &sc) {
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return std::nullopt;
-
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return std::nullopt;
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return std::nullopt;
-
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
-    return std::nullopt;
+  auto [demangled_name, info] = *info_or_err;
 
-  if (info->QualifiersRange.first < info->ArgumentsRange.second)
-    return std::nullopt;
+  if (info.QualifiersRange.first < info.ArgumentsRange.second)
+    return llvm::createStringError("Qualifiers range is invalid.");
 
-  return demangled_name.slice(info->ArgumentsRange.second,
-                              info->QualifiersRange.first);
+  return demangled_name.slice(info.ArgumentsRange.second,
+                              info.QualifiersRange.first);
 }
 
-static std::optional<llvm::StringRef>
+static llvm::Expected<llvm::StringRef>
 GetDemangledScope(const SymbolContext &sc) {
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return std::nullopt;
-
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return std::nullopt;
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return std::nullopt;
-
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
-    return std::nullopt;
+  auto [demangled_name, info] = *info_or_err;
 
-  if (info->ScopeRange.second < info->ScopeRange.first)
-    return std::nullopt;
+  if (info.ScopeRange.second < info.ScopeRange.first)
+    return llvm::createStringError("Info do not have basename range.");
 
-  return demangled_name.slice(info->ScopeRange.first, info->ScopeRange.second);
+  return demangled_name.slice(info.ScopeRange.first, info.ScopeRange.second);
 }
 
 /// Handles anything printed after the FunctionEncoding ItaniumDemangle
 /// node. Most notably the DotSUffix node.
-static std::optional<llvm::StringRef>
+static llvm::Expected<llvm::StringRef>
 GetDemangledFunctionSuffix(const SymbolContext &sc) {
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return std::nullopt;
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err)
+    return info_or_err.takeError();
 
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return std::nullopt;
+  auto [demangled_name, info] = *info_or_err;
 
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return std::nullopt;
-
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
-    return std::nullopt;
-
-  return demangled_name.slice(info->SuffixRange.first,
-                              info->SuffixRange.second);
+  return demangled_name.slice(info.SuffixRange.first, info.SuffixRange.second);
 }
 
 static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
   assert(sc.symbol);
 
-  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
-  if (!mangled)
-    return false;
-
-  auto demangled_name = mangled.GetDemangledName().GetStringRef();
-  if (demangled_name.empty())
-    return false;
-
-  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
-  if (!info)
-    return false;
-
-  // Function without a basename is nonsense.
-  if (!info->hasBasename())
+  auto info_or_err = GetAndValidateInfo(sc);
+  if (!info_or_err) {
+    info_or_err.takeError();
     return false;
+  }
+  auto [demangled_name, info] = *info_or_err;
 
-  if (info->ArgumentsRange.second < info->ArgumentsRange.first)
+  if (info.ArgumentsRange.second < info.ArgumentsRange.first)
     return false;
 
-  s << demangled_name.slice(info->ArgumentsRange.first,
-                            info->ArgumentsRange.second);
+  s << demangled_name.slice(info.ArgumentsRange.first,
+                            info.ArgumentsRange.second);
 
   return true;
 }
@@ -1954,32 +1895,37 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
     FormatEntity::Entry::Type type, Stream &s) {
   switch (type) {
   case FormatEntity::Entry::Type::FunctionScope: {
-    std::optional<llvm::StringRef> scope = GetDemangledScope(sc);
-    if (!scope)
+    auto scope_or_err = GetDemangledScope(sc);
+    if (!scope_or_err) {
+      llvm::consumeError(scope_or_err.takeError());
       return false;
+    }
 
-    s << *scope;
+    s << *scope_or_err;
 
     return true;
   }
 
   case FormatEntity::Entry::Type::FunctionBasename: {
-    std::optional<llvm::StringRef> name = GetDemangledBasename(sc);
-    if (!name)
+    auto name_or_err = GetDemangledBasename(sc);
+    if (!name_or_err) {
+      llvm::consumeError(name_or_err.takeError());
       return false;
+    }
 
-    s << *name;
+    s << *name_or_err;
 
     return true;
   }
 
   case FormatEntity::Entry::Type::FunctionTemplateArguments: {
-    std::optional<llvm::StringRef> template_args =
-        GetDemangledTemplateArguments(sc);
-    if (!template_args)
+    auto template_args_or_err = GetDemangledTemplateArguments(sc);
+    if (!template_args_or_err) {
+      llvm::consumeError(template_args_or_err.takeError());
       return false;
+    }
 
-    s << *template_args;
+    s << *template_args_or_err;
 
     return true;
   }
@@ -2008,38 +1954,46 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
     return true;
   }
   case FormatEntity::Entry::Type::FunctionReturnRight: {
-    std::optional<llvm::StringRef> return_rhs = GetDemangledReturnTypeRHS(sc);
-    if (!return_rhs)
+    auto return_rhs_or_err = GetDemangledReturnTypeRHS(sc);
+    if (!return_rhs_or_err) {
+      llvm::consumeError(return_rhs_or_err.takeError());
       return false;
+    }
 
-    s << *return_rhs;
+    s << *return_rhs_or_err;
 
     return true;
   }
   case FormatEntity::Entry::Type::FunctionReturnLeft: {
-    std::optional<llvm::StringRef> return_lhs = GetDemangledReturnTypeLHS(sc);
-    if (!return_lhs)
+    auto return_lhs_or_err = GetDemangledReturnTypeLHS(sc);
+    if (!return_lhs_or_err) {
+      llvm::consumeError(return_lhs_or_err.takeError());
       return false;
+    }
 
-    s << *return_lhs;
+    s << *return_lhs_or_err;
 
     return true;
   }
   case FormatEntity::Entry::Type::FunctionQualifiers: {
-    std::optional<llvm::StringRef> quals = GetDemangledFunctionQualifiers(sc);
-    if (!quals)
+    auto quals_or_err = GetDemangledFunctionQualifiers(sc);
+    if (!quals_or_err) {
+      llvm::consumeError(quals_or_err.takeError());
       return false;
+    }
 
-    s << *quals;
+    s << *quals_or_err;
 
     return true;
   }
   case FormatEntity::Entry::Type::FunctionSuffix: {
-    std::optional<llvm::StringRef> suffix = GetDemangledFunctionSuffix(sc);
-    if (!suffix)
+    auto suffix_or_err = GetDemangledFunctionSuffix(sc);
+    if (!suffix_or_err) {
+      llvm::consumeError(suffix_or_err.takeError());
       return false;
+    }
 
-    s << *suffix;
+    s << *suffix_or_err;
 
     return true;
   }

if (!info->hasBasename())
auto info_or_err = GetAndValidateInfo(sc);
if (!info_or_err) {
llvm::consumeError(info_or_err.takeError());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we log here instead of consuming the error?

Something like:

Suggested change
llvm::consumeError(info_or_err.takeError());
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), info_or_err.takeError(), "Failed to retrieve demangled info: {0}" 

Might need to downgrade it to LLDB_LOG_ERRORV if we find that this is a common/unimportant error path

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same applies to all the other places where we consumeError

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks! LLDB_LOG_ERROR seems to be reasonable for now, I did not encounter an error message while testing on a small C++ program.

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable, modulo the logging comment


auto demangled_name = mangled.GetDemangledName().GetStringRef();
if (demangled_name.empty())
return std::nullopt;
return llvm::createStringError("Function does not have a demangled name.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return llvm::createStringError("Function does not have a demangled name.");
return llvm::createStringError("Function '%s' does not have a demangled name.", mangled.GetMangledName().AsCString(""));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added better messages for all the createStringError.


const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
if (!info)
return std::nullopt;
return llvm::createStringError("Function does not have demangled info.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return llvm::createStringError("Function does not have demangled info.");
return llvm::createStringError("Function '%s' does not have demangled info.", demangled_name.data());


// Function without a basename is nonsense.
if (!info->hasBasename())
return std::nullopt;
return llvm::createStringError("Info do not have basename range.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return llvm::createStringError("Info do not have basename range.");
return llvm::createStringError("DemangledInfo for '%s' do not have basename range.", demangled_name.data());

if (!info)
return std::nullopt;
if (info.ScopeRange.first >= demangled_name.size())
return llvm::createStringError("Scope range is invalid.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return llvm::createStringError("Scope range is invalid.");
return llvm::createStringError("Scope range for '%s' is invalid.", demangled_name.data());

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you similarly include the demangled_name in the error message elsewhere too?

auto name_or_err = GetDemangledBasename(sc);
if (!name_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), name_or_err.takeError(),
"Failed to retrieve basename: {0}");
Copy link
Member

@Michael137 Michael137 Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Failed to retrieve basename: {0}");
"Failed to handle ${function.basename} frame-format variable: {0}");

And do this for the other messages in this switch too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added better messages for all the LLDB_LOG_ERROR.

@charles-zablit
Copy link
Contributor Author

I think we should wait before the following PR gets merged before merging, in order to use the new has methods.

@charles-zablit charles-zablit force-pushed the charles-zablit/lldb/use-llvmExpected branch from 1af4c9e to 6d8e8c0 Compare June 19, 2025 13:54
@charles-zablit
Copy link
Contributor Author

I think we should wait before the following PR gets merged before merging, in order to use the new has methods.

Done ✅

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just left a couple follow-up comments. Otherwise LGTM!

if (!quals_or_err) {
LLDB_LOG_ERROR(
GetLog(LLDBLog::Language), quals_or_err.takeError(),
"Failed to handle ${function.qualifiers} frame-format variable: {0}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I think you need to escape the { here. Since that's the syntax for specifying the format index. I think {{ is the way to do that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, thanks!

Copy link

github-actions bot commented Jun 20, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

if (!info->hasBasename())
return std::nullopt;
if (!info.hasQualifiers())
return llvm::createStringError("Qualifiers range for '%s' is invalid.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, not having qualifiers on a demangled name doesn't necessarily mean this is fatal. This explains the latest linux failures. Some methods just don't have qualifiers. I guess we need to return "" in that case. Should hasQualifiers also accept cases where QualifiersRange.start == QualifiersRange.end? Which just means they don't exist, but didn't fail to parse. I'm also happy to just remove this check. I think that's why i used to only check for hasBasename.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add another method called areQualifiersEmpty (or better name) which checks if QualifiersRange.start == QualifiersRange.end. The check would look like

if(!hasQualifiers() && !areQualifiersEmpty())
    return createStringError(...);

return demangled_name.slice(...);

This way we keep the semantic meaning of hasQualifiers and we can still surface parsing errors, which we would not be able to do if we remove the check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up adding a isXEmpty() method for each range which checks if xRange.first == xRange.second. This fixes the test.

@@ -74,24 +74,48 @@ struct DemangledNameInfo {
return BasenameRange.second > BasenameRange.first;
}

/// Returns \c true if `BasenameRange` is empty.
bool isBasenameEmpty() const {
return BasenameRange.first == BasenameRange.second;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I think I'd prefer having only a single API that tells us "do we have a valid entity or not". E.g., hasValidQualifiers/hasValidBasename/etc. Is there a reason we can't just modify the existing hasXXX helpers to be Range.second >= Range.first? If we are going to call !hasXXX && !isEmpty then might as well fold them into a single API.

But if there's reasons we can't do that, this seems fine too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that since we are calling !hasX && !isEmpty everywhere, me might just as well squash them. When doing so, the only problem I have noticed is that some tests break, such as when demangling Zinvalid which technically has no basename, but with this new implementation hasBasename returns true.

Overall, I still think it's best to collapse everything into one method like you suggested 👍

Copy link
Member

@Michael137 Michael137 Jun 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adjusting. Mostly looks good now

Though I don't think hasBasename should allow for start == end. That's the one range that all DemangledInfo objects need to have to be considered valid. Could we keep that as end > start? I don't think that should break anything. Probably worth adding a comment there why it's not >=

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to > instead of >= for hasBasename. This "fixed" the tests that I originally broke 👍

@charles-zablit charles-zablit merged commit a0329ea into llvm:main Jun 23, 2025
7 checks passed
miguelcsx pushed a commit to miguelcsx/llvm-project that referenced this pull request Jun 23, 2025
…lvm#144731)

Upgrade the callees of `HandleFrameFormatVariable`
(`GetDemangledTemplateArguments`, etc), to return a `llvm::Expected`
instead of an `std::optional`.

This patch also bundles the logic of validating the demangled name and
information into a single reusable function to reduce code duplication.
Jaddyen pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 23, 2025
…lvm#144731)

Upgrade the callees of `HandleFrameFormatVariable`
(`GetDemangledTemplateArguments`, etc), to return a `llvm::Expected`
instead of an `std::optional`.

This patch also bundles the logic of validating the demangled name and
information into a single reusable function to reduce code duplication.
charles-zablit added a commit to charles-zablit/llvm-project that referenced this pull request Jun 24, 2025
…lvm#144731)

Upgrade the callees of `HandleFrameFormatVariable`
(`GetDemangledTemplateArguments`, etc), to return a `llvm::Expected`
instead of an `std::optional`.

This patch also bundles the logic of validating the demangled name and
information into a single reusable function to reduce code duplication.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants