diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index d6bc16b6350f..abfec13a995b 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -24,6 +24,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/iterator.h" using namespace clang; @@ -50,12 +51,64 @@ static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) { return nullptr; } +/// The name of a decomposition declaration. +struct DecompositionDeclName { + using BindingArray = ArrayRef; + + /// Representative example of a set of bindings with these names. + BindingArray Bindings; + + /// Iterators over the sequence of identifiers in the name. + struct Iterator + : llvm::iterator_adaptor_base { + Iterator(BindingArray::const_iterator It) : iterator_adaptor_base(It) {} + const IdentifierInfo *operator*() const { + return (*this->I)->getIdentifier(); + } + }; + Iterator begin() const { return Iterator(Bindings.begin()); } + Iterator end() const { return Iterator(Bindings.end()); } +}; +} + +namespace llvm { +template<> +struct DenseMapInfo { + using ArrayInfo = llvm::DenseMapInfo>; + using IdentInfo = llvm::DenseMapInfo; + static DecompositionDeclName getEmptyKey() { + return {ArrayInfo::getEmptyKey()}; + } + static DecompositionDeclName getTombstoneKey() { + return {ArrayInfo::getTombstoneKey()}; + } + static unsigned getHashValue(DecompositionDeclName Key) { + assert(!isEqual(Key, getEmptyKey()) && !isEqual(Key, getTombstoneKey())); + return llvm::hash_combine_range(Key.begin(), Key.end()); + } + static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) { + if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey())) + return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey()); + if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey())) + return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getTombstoneKey()); + return LHS.Bindings.size() == RHS.Bindings.size() && + std::equal(LHS.begin(), LHS.end(), RHS.begin()); + } +}; +} + +namespace { + /// \brief Keeps track of the mangled names of lambda expressions and block /// literals within a particular context. class ItaniumNumberingContext : public MangleNumberingContext { llvm::DenseMap ManglingNumbers; llvm::DenseMap VarManglingNumbers; llvm::DenseMap TagManglingNumbers; + llvm::DenseMap + DecompsitionDeclManglingNumbers; public: unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { @@ -82,9 +135,14 @@ public: /// Variable decls are numbered by identifier. unsigned getManglingNumber(const VarDecl *VD, unsigned) override { + if (auto *DD = dyn_cast(VD)) + return ++DecompsitionDeclManglingNumbers[ + DecompositionDeclName{DD->bindings()}]; + const IdentifierInfo *Identifier = VD->getIdentifier(); if (!Identifier) { - // VarDecl without an identifier represents an anonymous union declaration. + // VarDecl without an identifier represents an anonymous union + // declaration. Identifier = findAnonymousUnionVarDeclName(*VD); } return ++VarManglingNumbers[Identifier]; diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 7a4221784ad3..3c9b181f1c8f 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -76,4 +76,9 @@ template void dependent_foreach(T t) { a,b,c; } +struct PR37352 { + int n; + void f() { static auto [a] = *this; } // expected-error {{cannot be declared 'static'}} +}; + // FIXME: by-value array copies