[PATCH] D17565: [Support] Add a fancy helper function to get a static name for a type.

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 24 13:11:25 PST 2016


Chandler Carruth <chandlerc at gmail.com> writes:
> chandlerc created this revision.
> chandlerc added reviewers: bogner, joker.eph, rsmith.
> chandlerc added a subscriber: llvm-commits.
> Herald added a subscriber: mcrosier.
>
> This extracts the type name from __PRETTY_FUNCTION__ for compilers that
> support it (I've opted Clang, GCC, and ICC into this as I've tested that
> they work) and it uses typeid and typeinfo in a pattern that work with
> MSVC even without RTTI. The routine falls back gracefully on a stub
> "UNKNOWN_TYPE" string with compilers or formats it doesn't understand.
>
> This should be enough for a lot of common cases in LLVM where the real
> goal is just to log or print a type name as a debugging aid, and save
> a ton of boilerplate in the process.

I'll let others weigh in on whether or not they think this is insane,
but it'll certainly be useful.

It's probably worth mentioning the use case you have in mind for this in
the commit message, though. That is, reducing the getName() boiler plate
in new-style passes.

> The design and implementation is based on a bunch of advice and
> discussion with Richard Smith and experimenting with most versions of
> Clang, GCC, and MSVC 2015. We've also checked that ICC does something
> reasonable and I'll watch the build bots for other compilers. It'd be
> great if someone could contribute logic for xlC and/or other toolchains.
>
> Comments or suggestions about how to make this better welcome. Hoping to
> land this when the bots aren't too busy (which is not tonight with the
> llvm.org hiccups) so tossing it out for review.
>
> http://reviews.llvm.org/D17565
>
> Files:
>   include/llvm/Support/TypeName.h
>   unittests/Support/CMakeLists.txt
>   unittests/Support/TypeNameTest.cpp
>
> Index: unittests/Support/TypeNameTest.cpp
> ===================================================================
> --- /dev/null
> +++ unittests/Support/TypeNameTest.cpp
> @@ -0,0 +1,49 @@
> +//===- TypeNameTest.cpp ---------------------------------------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Support/TypeName.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "gtest/gtest.h"
> +
> +using namespace llvm;
> +
> +namespace {
> +namespace N1 {
> +struct S1 {};
> +class C1 {};
> +union U1 {};
> +}
> +
> +TEST(TypeNameTest, Names) {
> +  struct S2 {};
> +
> +  StringRef S1Name = getTypeName<N1::S1>();
> +  StringRef C1Name = getTypeName<N1::C1>();
> +  StringRef U1Name = getTypeName<N1::U1>();
> +  StringRef S2Name = getTypeName<S2>();
> +
> +#if defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER) ||    \
> +    defined(_MSC_VER)
> +  EXPECT_TRUE(S1Name.endswith("::N1::S1")) << S1Name.str();
> +  EXPECT_TRUE(C1Name.endswith("::N1::C1")) << C1Name.str();
> +  EXPECT_TRUE(U1Name.endswith("::N1::U1")) << U1Name.str();
> +#ifdef __clang__
> +  EXPECT_TRUE(S2Name.endswith("S2")) << S2Name.str();
> +#else
> +  EXPECT_TRUE(S2Name.endswith("::S2")) << S2Name.str();
> +#endif
> +#else
> +  EXPECT_EQ("UNKNOWN_TYPE", S1Name);
> +  EXPECT_EQ("UNKNOWN_TYPE", C1Name);
> +  EXPECT_EQ("UNKNOWN_TYPE", U1Name);
> +  EXPECT_EQ("UNKNOWN_TYPE", S2Name);
> +#endif
> +}
> +
> +} // end anonymous namespace
> Index: unittests/Support/CMakeLists.txt
> ===================================================================
> --- unittests/Support/CMakeLists.txt
> +++ unittests/Support/CMakeLists.txt
> @@ -42,6 +42,7 @@
>    ThreadPool.cpp
>    TimerTest.cpp
>    TimeValueTest.cpp
> +  TypeNameTest.cpp
>    TrailingObjectsTest.cpp
>    UnicodeTest.cpp
>    YAMLIOTest.cpp
> Index: include/llvm/Support/TypeName.h
> ===================================================================
> --- /dev/null
> +++ include/llvm/Support/TypeName.h
> @@ -0,0 +1,62 @@
> +//===- TypeName.h -----------------------------------------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_SUPPORT_TYPENAME_H
> +#define LLVM_SUPPORT_TYPENAME_H
> +
> +#include "llvm/ADT/StringRef.h"
> +#include <string.h>
> +
> +#ifdef _MSC_VER
> +// We use typeinfo below which MSVC supports in restricted circumstances even
> +// when RTTI is disabled.
> +#include <typeinfo>
> +#endif
> +
> +namespace llvm {
> +
> +/// We provide a function which tries to compute the (demangled) name of a type
> +/// statically.
> +///
> +/// This routine may fail on some platforms or for particularly unusual types.
> +/// Do not use it for anything other than logging and debugging aids. It isn't
> +/// portable or dependendable in any real sense.
> +///
> +/// The returned const char * will point to a static storage duration C-string.
> +template <typename DesiredTypeName>
> +inline StringRef getTypeName() {
> +#if defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER)
> +  StringRef Name = __PRETTY_FUNCTION__;
> +  StringRef Key = "DesiredTypeName = ";
> +  Name = Name.substr(Name.find(Key));
> +  if (Name.empty() || !Name.endswith("]"))
> +    return "UNKNOWN_TYPE";

Would it make sense to assert here? I'd rather not allow in-tree uses to
hit this case, since it would degrade the debugging experience and could
pretty easily go unnoticed for some time.

> +
> +  return Name.drop_front(Key.size()).drop_back(1);
> +#elif defined(_MSC_VER)
> +  StringRef Name = typeid(T).name();
> +  if (Name.startswith("struct "))
> +    return Name.substr(strlen("struct "));
> +  if (Name.startswith("class "))
> +    return Name.substr(strlen("class "));
> +  if (Name.startswith("union "))
> +    return Name.substr(strlen("union "));
> +
> +  // Otherwise, this is likely a mangled name which is better than nothing.
> +  return Name;
> +#else
> +  // No known technique for statically extracting a type name on this compiler.
> +  // We return a string that is unlikely to look like any type in LLVM.
> +  return "UNKNOWN_TYPE";
> +#endif
> +}
> +
> +}
> +
> +#endif


More information about the llvm-commits mailing list