summaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
authorShafik Yaghmour <syaghmour@apple.com>2018-09-19 18:07:05 +0000
committerShafik Yaghmour <syaghmour@apple.com>2018-09-19 18:07:05 +0000
commit795e5ce85525a3a430aed6b847bc2af52acb42a1 (patch)
tree30419bdc2bfecd19c4338c7b852d3ad1d1184f14 /lldb
parent2e597b3613cc4d9e66c6b3b428e23f4b089a7086 (diff)
[DataFormatters] Add formatter for C++17 std::variant
rdar://problem/43691454 Patch by Shafik Yaghmour. Differential Revision: https://reviews.llvm.org/D51520
Diffstat (limited to 'lldb')
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj8
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/Makefile7
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py81
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/main.cpp60
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp10
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp256
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h31
9 files changed, 458 insertions, 0 deletions
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index 3cbd4d99a72..2d80648a7a2 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -401,6 +401,8 @@
AF9FF1F71FAA79FE00474976 /* LibCxxQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9FF1F61FAA79FE00474976 /* LibCxxQueue.cpp */; };
AF9FF1F51FAA79A400474976 /* LibCxxTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9FF1F41FAA79A400474976 /* LibCxxTuple.cpp */; };
945261C41B9A11FC00BF138D /* LibCxxUnorderedMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261BA1B9A11E800BF138D /* LibCxxUnorderedMap.cpp */; };
+ E414F6F121388F6C00C50BC6 /* LibCxxVariant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E414F6F021388F6B00C50BC6 /* LibCxxVariant.cpp */; };
+ E414F6EE21388F0300C50BC6 /* LibCxxVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = E414F6ED21388F0200C50BC6 /* LibCxxVariant.h */; };
945261C51B9A11FC00BF138D /* LibCxxVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261BB1B9A11E800BF138D /* LibCxxVector.cpp */; };
945261C61B9A11FC00BF138D /* LibStdcpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261BC1B9A11E800BF138D /* LibStdcpp.cpp */; };
4CDB8D6E1DBA91B6006C5B13 /* LibStdcppTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CDB8D681DBA91A6006C5B13 /* LibStdcppTuple.cpp */; };
@@ -2056,6 +2058,8 @@
AF9FF1F61FAA79FE00474976 /* LibCxxQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxQueue.cpp; path = Language/CPlusPlus/LibCxxQueue.cpp; sourceTree = "<group>"; };
AF9FF1F41FAA79A400474976 /* LibCxxTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxTuple.cpp; path = Language/CPlusPlus/LibCxxTuple.cpp; sourceTree = "<group>"; };
945261BA1B9A11E800BF138D /* LibCxxUnorderedMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxUnorderedMap.cpp; path = Language/CPlusPlus/LibCxxUnorderedMap.cpp; sourceTree = "<group>"; };
+ E414F6F021388F6B00C50BC6 /* LibCxxVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxVariant.cpp; path = Language/CPlusPlus/LibCxxVariant.cpp; sourceTree = "<group>"; };
+ E414F6ED21388F0200C50BC6 /* LibCxxVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibCxxVariant.h; path = Language/CPlusPlus/LibCxxVariant.h; sourceTree = "<group>"; };
945261BB1B9A11E800BF138D /* LibCxxVector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxVector.cpp; path = Language/CPlusPlus/LibCxxVector.cpp; sourceTree = "<group>"; };
945261BC1B9A11E800BF138D /* LibStdcpp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibStdcpp.cpp; path = Language/CPlusPlus/LibStdcpp.cpp; sourceTree = "<group>"; };
945261BD1B9A11E800BF138D /* LibStdcpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LibStdcpp.h; path = Language/CPlusPlus/LibStdcpp.h; sourceTree = "<group>"; };
@@ -6475,6 +6479,8 @@
AF9FF1F61FAA79FE00474976 /* LibCxxQueue.cpp */,
AF9FF1F41FAA79A400474976 /* LibCxxTuple.cpp */,
945261BA1B9A11E800BF138D /* LibCxxUnorderedMap.cpp */,
+ E414F6ED21388F0200C50BC6 /* LibCxxVariant.h */,
+ E414F6F021388F6B00C50BC6 /* LibCxxVariant.cpp */,
945261BB1B9A11E800BF138D /* LibCxxVector.cpp */,
945261BD1B9A11E800BF138D /* LibStdcpp.h */,
945261BC1B9A11E800BF138D /* LibStdcpp.cpp */,
@@ -7081,6 +7087,7 @@
6D0F614F1C80AB0C00A4ECEE /* JavaLanguageRuntime.h in Headers */,
AF27AD561D3603EA00CF2833 /* DynamicLoaderDarwin.h in Headers */,
AFCB2BBE1BF577F40018B553 /* PythonExceptionState.h in Headers */,
+ E414F6EE21388F0300C50BC6 /* LibCxxVariant.h in Headers */,
267F684B1CC02DED0086832B /* ABISysV_s390x.h in Headers */,
AF8AD6311BEC28A400150209 /* PlatformAppleWatchSimulator.h in Headers */,
);
@@ -7936,6 +7943,7 @@
AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */,
AF254E31170CCC33007AE5C9 /* PlatformDarwinKernel.cpp in Sources */,
2689004913353E0400698AC0 /* Scalar.cpp in Sources */,
+ E414F6F121388F6C00C50BC6 /* LibCxxVariant.cpp in Sources */,
263FDE601A79A01500E68013 /* FormatEntity.cpp in Sources */,
AF8AD62E1BEC28A400150209 /* PlatformAppleTVSimulator.cpp in Sources */,
2689004A13353E0400698AC0 /* SearchFilter.cpp in Sources */,
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/Makefile
new file mode 100644
index 00000000000..a6ea665ef63
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/Makefile
@@ -0,0 +1,7 @@
+LEVEL = ../../../../../make
+
+CXX_SOURCES := main.cpp
+
+USE_LIBCPP := 1
+include $(LEVEL)/Makefile.rules
+CXXFLAGS += -std=c++17
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py
new file mode 100644
index 00000000000..9ea7ac33166
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py
@@ -0,0 +1,81 @@
+"""
+Test lldb data formatter subsystem.
+"""
+
+from __future__ import print_function
+
+
+import os
+import time
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class LibcxxOptionalDataFormatterTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @add_test_categories(["libc++"])
+ ## We are skipping clang version less that 5.0 since this test requires -std=c++17
+ @skipIf(oslist=no_match(["macosx"]), compiler="clang", compiler_version=['<', '5.0'])
+ ## We are skipping gcc version less that 5.1 since this test requires -std=c++17
+ @skipIf(compiler="gcc", compiler_version=['<', '5.1'])
+
+ def test_with_run_command(self):
+ """Test that that file and class static variables display correctly."""
+ self.build()
+
+ (self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here',
+ lldb.SBFileSpec("main.cpp", False))
+
+ self.runCmd( "frame variable has_variant" )
+
+ output = self.res.GetOutput()
+
+ ## The variable has_variant tells us if the test program
+ ## detected we have a sufficient libc++ version to support variant
+ ## false means we do not and therefore should skip the test
+ if output.find("(bool) has_variant = false") != -1 :
+ self.skipTest( "std::variant not supported" )
+
+ lldbutil.continue_to_breakpoint(self.process, bkpt)
+
+ self.expect("frame variable v1",
+ substrs=['v1 = Active Type = int {',
+ 'Value = 12',
+ '}'])
+
+ self.expect("frame variable v1_ref",
+ substrs=['v1_ref = Active Type = int : {',
+ 'Value = 12',
+ '}'])
+
+ self.expect("frame variable v_v1",
+ substrs=['v_v1 = Active Type = std::__1::variant<int, double, char> {',
+ 'Value = Active Type = int {',
+ 'Value = 12',
+ '}',
+ '}'])
+
+ lldbutil.continue_to_breakpoint(self.process, bkpt)
+
+ self.expect("frame variable v1",
+ substrs=['v1 = Active Type = double {',
+ 'Value = 2',
+ '}'])
+
+ lldbutil.continue_to_breakpoint(self.process, bkpt)
+
+ self.expect("frame variable v2",
+ substrs=['v2 = Active Type = double {',
+ 'Value = 2',
+ '}'])
+
+ self.expect("frame variable v3",
+ substrs=['v3 = Active Type = char {',
+ 'Value = \'A\'',
+ '}'])
+
+ self.expect("frame variable v_no_value",
+ substrs=['v_no_value = No Value'])
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/main.cpp
new file mode 100644
index 00000000000..c0bc4ae12c1
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/variant/main.cpp
@@ -0,0 +1,60 @@
+#include <cstdio>
+#include <string>
+#include <vector>
+
+// If we have libc++ 4.0 or greater we should have <variant>
+// According to libc++ C++1z status page https://libcxx.llvm.org/cxx1z_status.html
+#if _LIBCPP_VERSION >= 4000
+#include <variant>
+#define HAVE_VARIANT 1
+#else
+#define HAVE_VARIANT 0
+#endif
+
+struct S {
+ operator int() { throw 42; }
+} ;
+
+
+int main()
+{
+ bool has_variant = HAVE_VARIANT ;
+
+ printf( "%d\n", has_variant ) ; // break here
+
+#if HAVE_VARIANT == 1
+ std::variant<int, double, char> v1;
+ std::variant<int, double, char> &v1_ref = v1;
+ std::variant<int, double, char> v2;
+ std::variant<int, double, char> v3;
+ std::variant<std::variant<int,double,char>> v_v1 ;
+ std::variant<int, double, char> v_no_value;
+
+ v1 = 12; // v contains int
+ v_v1 = v1 ;
+ int i = std::get<int>(v1);
+ printf( "%d\n", i ); // break here
+
+ v2 = 2.0 ;
+ double d = std::get<double>(v2) ;
+ printf( "%f\n", d );
+
+ v3 = 'A' ;
+ char c = std::get<char>(v3) ;
+ printf( "%d\n", c );
+
+ // Checking v1 above and here to make sure we done maintain the incorrect
+ // state when we change its value.
+ v1 = 2.0;
+ d = std::get<double>(v1) ;
+ printf( "%f\n", d ); // break here
+
+ try {
+ v_no_value.emplace<0>(S());
+ } catch( ... ) {}
+
+ printf( "%zu\n", v_no_value.index() ) ;
+#endif
+
+ return 0; // break here
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index eb0d880c641..715334412f8 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxQueue.cpp
LibCxxTuple.cpp
LibCxxUnorderedMap.cpp
+ LibCxxVariant.cpp
LibCxxVector.cpp
LibStdcpp.cpp
LibStdcppTuple.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 7ce21146683..33bf7096d62 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -39,6 +39,7 @@
#include "CxxStringTypes.h"
#include "LibCxx.h"
#include "LibCxxAtomic.h"
+#include "LibCxxVariant.h"
#include "LibStdcpp.h"
using namespace lldb;
@@ -516,6 +517,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::optional synthetic children",
ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"),
stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
+ "libc++ std::variant synthetic children",
+ ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"),
+ stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
@@ -617,6 +622,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::optional summary provider",
ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"),
stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxVariantSummaryProvider,
+ "libc++ std::variant summary provider",
+ ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"),
+ stl_summary_flags, true);
stl_summary_flags.SetSkipPointers(true);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index 06f5817845b..871268720c7 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -142,6 +142,10 @@ SyntheticChildrenFrontEnd *
LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP valobj_sp);
+SyntheticChildrenFrontEnd *
+LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
} // namespace formatters
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
new file mode 100644
index 00000000000..04d8b804434
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
@@ -0,0 +1,256 @@
+//===-- LibCxxVariant.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxxVariant.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/ScopeExit.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// libc++ variant implementation contains two members that we care about both
+// are contained in the __impl member.
+// - __index which tells us which of the variadic template types is the active
+// type for the variant
+// - __data is a variadic union which recursively contains itself as member
+// which refers to the tailing variadic types.
+// - __head which refers to the leading non pack type
+// - __value refers to the actual value contained
+// - __tail which refers to the remaining pack types
+//
+// e.g. given std::variant<int,double,char> v1
+//
+// (lldb) frame var -R v1.__impl.__data
+//(... __union<... 0, int, double, char>) v1.__impl.__data = {
+// ...
+// __head = {
+// __value = ...
+// }
+// __tail = {
+// ...
+// __head = {
+// __value = ...
+// }
+// __tail = {
+// ...
+// __head = {
+// __value = ...
+// ...
+//
+// So given
+// - __index equal to 0 the active value is contained in
+//
+// __data.__head.__value
+//
+// - __index equal to 1 the active value is contained in
+//
+// __data.__tail.__head.__value
+//
+// - __index equal to 2 the active value is contained in
+//
+// __data.__tail.__tail.__head.__value
+//
+
+namespace {
+// libc++ std::variant index could have one of three states
+// 1) VALID, we can obtain it and its not variant_npos
+// 2) INVALID, we can't obtain it or it is not a type we expect
+// 3) NPOS, its value is variant_npos which means the variant has no value
+enum class LibcxxVariantIndexValidity { VALID, INVALID, NPOS };
+
+LibcxxVariantIndexValidity
+LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
+ ValueObjectSP index_sp(
+ impl_sp->GetChildMemberWithName(ConstString("__index"), true));
+
+ if (!index_sp)
+ return LibcxxVariantIndexValidity::INVALID;
+
+ int64_t index_value = index_sp->GetValueAsSigned(0);
+
+ if (index_value == -1)
+ return LibcxxVariantIndexValidity::NPOS;
+
+ return LibcxxVariantIndexValidity::VALID;
+}
+
+llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
+ ValueObjectSP index_sp(
+ impl_sp->GetChildMemberWithName(ConstString("__index"), true));
+
+ if (!index_sp)
+ return {};
+
+ return {index_sp->GetValueAsUnsigned(0)};
+}
+
+ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
+ ValueObjectSP data_sp(
+ impl_sp->GetChildMemberWithName(ConstString("__data"), true));
+
+ if (!data_sp)
+ return ValueObjectSP{};
+
+ ValueObjectSP current_level = data_sp;
+ for (uint64_t n = index; n != 0; --n) {
+ ValueObjectSP tail_sp(
+ current_level->GetChildMemberWithName(ConstString("__tail"), true));
+
+ if (!tail_sp)
+ return ValueObjectSP{};
+
+ current_level = tail_sp;
+ }
+
+ return current_level->GetChildMemberWithName(ConstString("__head"), true);
+};
+} // namespace
+
+namespace lldb_private {
+namespace formatters {
+bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP impl_sp(
+ valobj_sp->GetChildMemberWithName(ConstString("__impl"), true));
+
+ if (!impl_sp)
+ return false;
+
+ LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
+
+ if (validity == LibcxxVariantIndexValidity::INVALID)
+ return false;
+
+ if (validity == LibcxxVariantIndexValidity::NPOS) {
+ stream.Printf(" No Value");
+ return true;
+ }
+
+ auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
+
+ if (!optional_index_value)
+ return false;
+
+ uint64_t index_value = *optional_index_value;
+
+ ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
+
+ if (!nth_head)
+ return false;
+
+ CompilerType head_type = nth_head->GetCompilerType();
+
+ if (!head_type)
+ return false;
+
+ CompilerType template_type = head_type.GetTypeTemplateArgument(1);
+
+ if (!template_type)
+ return false;
+
+ stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString());
+
+ return true;
+}
+} // namespace formatters
+} // namespace lldb_private
+
+namespace {
+class VariantFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ bool Update() override;
+ size_t CalculateNumChildren() override { return m_size; }
+ ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+private:
+ size_t m_size = 0;
+ ValueObjectSP m_base_sp;
+};
+} // namespace
+
+bool VariantFrontEnd::Update() {
+ m_size = 0;
+ ValueObjectSP impl_sp(
+ m_backend.GetChildMemberWithName(ConstString("__impl"), true));
+ if (!impl_sp)
+ return false;
+
+ LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
+
+ if (validity == LibcxxVariantIndexValidity::INVALID)
+ return false;
+
+ if (validity == LibcxxVariantIndexValidity::NPOS)
+ return true;
+
+ m_size = 1;
+
+ return false;
+}
+
+ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) {
+ if (idx >= m_size)
+ return ValueObjectSP();
+
+ ValueObjectSP impl_sp(
+ m_backend.GetChildMemberWithName(ConstString("__impl"), true));
+
+ auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
+
+ if (!optional_index_value)
+ return ValueObjectSP();
+
+ uint64_t index_value = *optional_index_value;
+
+ ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
+
+ if (!nth_head)
+ return ValueObjectSP();
+
+ CompilerType head_type = nth_head->GetCompilerType();
+
+ if (!head_type)
+ return ValueObjectSP();
+
+ CompilerType template_type = head_type.GetTypeTemplateArgument(1);
+
+ if (!template_type)
+ return ValueObjectSP();
+
+ ValueObjectSP head_value(
+ nth_head->GetChildMemberWithName(ConstString("__value"), true));
+
+ if (!head_value)
+ return ValueObjectSP();
+
+ return head_value->Clone(ConstString(ConstString("Value").AsCString()));
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new VariantFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h
new file mode 100644
index 00000000000..04834581963
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h
@@ -0,0 +1,31 @@
+//===-- LibCxxVariant.h -------------------------------------------*- C++
+//-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_LibCxxVariant_h_
+#define liblldb_LibCxxVariant_h_
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+bool LibcxxVariantSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::variant<>
+
+SyntheticChildrenFrontEnd *LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // liblldb_LibCxxVariant_h_