NFC: Make the copies of the demangler byte-for-byte identical

With this patch, the copies of the files ItaniumDemangle.h,
StringView.h, and Utility.h are kept byte-for-byte in sync between
libcxxabi and llvm. All differences (namespaces, fallthrough, and
unreachable macros) are defined in each copies' DemanglerConfig.h.

This patch also adds a script to copy changes from libcxxabi
(cp-to-llvm.sh), and a README.txt explaining the situation.

Differential revision: https://reviews.llvm.org/D53538

llvm-svn: 351474
This commit is contained in:
Erik Pilkington 2019-01-17 20:37:51 +00:00
parent 19c7db09aa
commit bb4d660781
10 changed files with 154 additions and 62 deletions

View File

@ -1,14 +1,16 @@
//===--- Compiler.h ---------------------------------------------*- C++ -*-===//
//===--- DemangleConfig.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a variety of feature test macros copied from
// include/llvm/Support/Compiler.h so that LLVMDemangle does not need to take
// a dependency on LLVMSupport.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_COMPILER_H
@ -37,57 +39,60 @@
#define __has_builtin(x) 0
#endif
#ifndef LLVM_GNUC_PREREQ
#ifndef DEMANGLE_GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define LLVM_GNUC_PREREQ(maj, min, patch) \
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
((maj) << 20) + ((min) << 10) + (patch))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#define LLVM_GNUC_PREREQ(maj, min, patch) \
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
#else
#define LLVM_GNUC_PREREQ(maj, min, patch) 0
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
#endif
#endif
#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
#else
#define LLVM_ATTRIBUTE_USED
#define DEMANGLE_ATTRIBUTE_USED
#endif
#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
#define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define LLVM_BUILTIN_UNREACHABLE __assume(false)
#define DEMANGLE_BUILTIN_UNREACHABLE __assume(false)
#endif
#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define LLVM_ATTRIBUTE_NOINLINE
#define DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
#if !defined(NDEBUG)
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
#else
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#define LLVM_FALLTHROUGH [[fallthrough]]
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define LLVM_FALLTHROUGH
#define DEMANGLE_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#define LLVM_FALLTHROUGH [[clang::fallthrough]]
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
#else
#define LLVM_FALLTHROUGH
#define DEMANGLE_FALLTHROUGH
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }
#endif

View File

@ -6,18 +6,22 @@
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Generic itanium demangler library. This file has two byte-per-byte identical
// copies in the source tree, one in libcxxabi, and the other in llvm.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_H
#define LLVM_DEMANGLE_ITANIUMDEMANGLE_H
#ifndef DEMANGLE_ITANIUMDEMANGLE_H
#define DEMANGLE_ITANIUMDEMANGLE_H
// FIXME: (possibly) incomplete list of features that clang mangles that this
// file does not yet support:
// - C++ modules TS
#include "llvm/Demangle/Compiler.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"
#include "DemangleConfig.h"
#include "StringView.h"
#include "Utility.h"
#include <cassert>
#include <cctype>
#include <cstdio>
@ -95,8 +99,8 @@
X(BracedExpr) \
X(BracedRangeExpr)
namespace llvm {
namespace itanium_demangle {
DEMANGLE_NAMESPACE_BEGIN
// Base class of all AST nodes. The AST is built by the parser, then is
// traversed by the printLeft/Right functions to produce a demangled string.
class Node {
@ -194,7 +198,7 @@ public:
virtual ~Node() = default;
#ifndef NDEBUG
LLVM_DUMP_METHOD void dump() const;
DEMANGLE_DUMP_METHOD void dump() const;
#endif
};
@ -1278,7 +1282,7 @@ public:
case SpecialSubKind::iostream:
return StringView("basic_iostream");
}
LLVM_BUILTIN_UNREACHABLE;
DEMANGLE_UNREACHABLE;
}
void printLeft(OutputStream &S) const override {
@ -1330,7 +1334,7 @@ public:
case SpecialSubKind::iostream:
return StringView("iostream");
}
LLVM_BUILTIN_UNREACHABLE;
DEMANGLE_UNREACHABLE;
}
void printLeft(OutputStream &S) const override {
@ -3467,7 +3471,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
Result = getDerived().parseFunctionType();
break;
}
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
}
case 'U': {
Result = getDerived().parseQualifiedType();
@ -3754,7 +3758,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
// substitution table.
return Sub;
}
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
}
// ::= <class-enum-type>
default: {
@ -5178,7 +5182,6 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
Alloc>::AbstractManglingParser;
};
} // namespace itanium_demangle
} // namespace llvm
DEMANGLE_NAMESPACE_END
#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_H
#endif // DEMANGLE_ITANIUMDEMANGLE_H

View File

@ -10,7 +10,7 @@
#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
#include "llvm/Demangle/Compiler.h"
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"

View File

@ -1,11 +1,31 @@
//===- MicrosoftDemangleNodes.h ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the AST nodes used in the MSVC demangler.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
#include "llvm/Demangle/Compiler.h"
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/StringView.h"
#include <array>
namespace llvm {
namespace itanium_demangle {
class OutputStream;
}
}
using llvm::itanium_demangle::OutputStream;
using llvm::itanium_demangle::StringView;
namespace llvm {
namespace ms_demangle {
@ -602,4 +622,4 @@ struct FunctionSymbolNode : public SymbolNode {
} // namespace ms_demangle
} // namespace llvm
#endif
#endif

View File

@ -0,0 +1,52 @@
Itanium Name Demangler Library
==============================
Introduction
------------
This directory contains the generic itanium name demangler library. The main
purpose of the library is to demangle C++ symbols, i.e. convert the string
"_Z1fv" into "f()". You can also use the CRTP base ManglingParser to perform
some simple analysis on the mangled name, or (in LLVM) use the opaque
ItaniumPartialDemangler to query the demangled AST.
Why are there multiple copies of the this library in the source tree?
---------------------------------------------------------------------
This directory is mirrored between libcxxabi/demangle and
llvm/include/llvm/Demangle. The simple reason for this is that both projects
need to demangle symbols, but neither can depend on each other. libcxxabi needs
the demangler to implement __cxa_demangle, which is part of the itanium ABI
spec. LLVM needs a copy for a bunch of places, but doesn't want to use the
system's __cxa_demangle because it a) might not be available (i.e., on Windows),
and b) probably isn't that up-to-date on the latest language features.
The copy of the demangler in LLVM has some extra stuff that aren't needed in
libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), which depend on the
shared generic components. Despite these differences, we want to keep the "core"
generic demangling library identical between both copies to simplify development
and testing.
If you're working on the generic library, then do the work first in libcxxabi,
then run the cp-to-llvm.sh script in src/demangle. This script takes as an
argument the path to llvm, and re-copies the changes you made to libcxxabi over.
Note that this script just blindly overwrites all changes to the generic library
in llvm, so be careful.
Because the core demangler needs to work in libcxxabi, everything needs to be
declared in an anonymous namespace (see DEMANGLE_NAMESPACE_BEGIN), and you can't
introduce any code that depends on the libcxx dylib.
Hopefully, when LLVM becomes a monorepo, we can de-duplicate this code, and have
both LLVM and libcxxabi depend on a shared demangler library.
Testing
-------
The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and
llvm/unittest/Demangle. The llvm directory should only get tests for stuff not
included in the core library. In the future though, we should probably move all
the tests to LLVM.
It is also a really good idea to run libFuzzer after non-trivial changes, see
libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and https://llvm.org/docs/LibFuzzer.html.

View File

@ -5,18 +5,22 @@
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
//
// This file contains a limited version of LLVM's StringView class. It is
// copied here so that LLVMDemangle need not take a dependency on LLVMSupport.
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_STRINGVIEW_H
#define LLVM_DEMANGLE_STRINGVIEW_H
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <algorithm>
#include <cassert>
#include <cstring>
DEMANGLE_NAMESPACE_BEGIN
class StringView {
const char *First;
const char *Last;
@ -43,7 +47,7 @@ public:
if (FindBegin < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
return static_cast<const char *>(P) - First;
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
@ -118,4 +122,6 @@ inline bool operator==(const StringView &LHS, const StringView &RHS) {
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -5,21 +5,24 @@
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler(s).
//
// This file contains several utility classes used by the demangle library.
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_UTILITY_H
#define LLVM_DEMANGLE_UTILITY_H
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "StringView.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputStream {
@ -184,4 +187,6 @@ inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
return true;
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -18,7 +18,7 @@
#include "llvm/Demangle/Demangle.h"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
#include "llvm/Demangle/Compiler.h"
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"
@ -265,7 +265,7 @@ Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
NI->Name = "`RTTI Complete Object Locator'";
break;
default:
LLVM_BUILTIN_UNREACHABLE;
DEMANGLE_UNREACHABLE;
}
QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();
@ -632,7 +632,7 @@ translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {
case FunctionIdentifierCodeGroup::DoubleUnder:
return DoubleUnder[Index];
}
LLVM_BUILTIN_UNREACHABLE;
DEMANGLE_UNREACHABLE;
}
IdentifierNode *
@ -1188,7 +1188,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
switch (MangledName.popFront()) {
case '1':
IsWcharT = true;
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
case '0':
break;
default:
@ -1255,7 +1255,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
Result->Char = CharKind::Char32;
break;
default:
LLVM_BUILTIN_UNREACHABLE;
DEMANGLE_UNREACHABLE;
}
const unsigned NumChars = BytesDecoded / CharBytes;
for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {
@ -2083,15 +2083,15 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
case 'J':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
case 'I':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
case 'H':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
case '1':
break;
default:
@ -2117,13 +2117,13 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
case 'G':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
case 'F':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
LLVM_FALLTHROUGH;
DEMANGLE_FALLTHROUGH;
case '0':
break;
default:

View File

@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
#include "llvm/Demangle/Compiler.h"
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/Utility.h"
#include <cctype>
#include <string>

View File

@ -22,6 +22,7 @@ using namespace llvm;
using llvm::itanium_demangle::ForwardTemplateReference;
using llvm::itanium_demangle::Node;
using llvm::itanium_demangle::NodeKind;
using llvm::itanium_demangle::StringView;
namespace {
struct FoldingSetNodeIDBuilder {