<div dir="ltr">The invented mangling for clang-cl turns out to not be correct :) <a href="https://bugs.llvm.org/show_bug.cgi?id=42093">https://bugs.llvm.org/show_bug.cgi?id=42093</a><div><br></div><div>Maybe it's better to add a "can't yet mangle" error, so that we don't silently do the wrong thing?</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Aug 14, 2016 at 9:41 PM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: rsmith<br>
Date: Sun Aug 14 20:33:41 2016<br>
New Revision: 278642<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=278642&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=278642&view=rev</a><br>
Log:<br>
P0217R3: code generation support for decomposition declarations.<br>
<br>
Added:<br>
    cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp<br>
Modified:<br>
    cfe/trunk/lib/AST/ASTContext.cpp<br>
    cfe/trunk/lib/AST/ItaniumMangle.cpp<br>
    cfe/trunk/lib/AST/MicrosoftMangle.cpp<br>
    cfe/trunk/lib/CodeGen/CGDecl.cpp<br>
    cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp<br>
<br>
Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTContext.cpp Sun Aug 14 20:33:41 2016<br>
@@ -8721,6 +8721,14 @@ bool ASTContext::DeclMustBeEmitted(const<br>
       !VD->evaluateValue())<br>
     return true;<br>
<br>
+  // Likewise, variables with tuple-like bindings are required if their<br>
+  // bindings have side-effects.<br>
+  if (auto *DD = dyn_cast<DecompositionDecl>(VD))<br>
+    for (auto *BD : DD->bindings())<br>
+      if (auto *BindingVD = BD->getHoldingVar())<br>
+        if (DeclMustBeEmitted(BindingVD))<br>
+          return true;<br>
+<br>
   return false;<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)<br>
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Sun Aug 14 20:33:41 2016<br>
@@ -1195,18 +1195,21 @@ void CXXNameMangler::mangleUnqualifiedNa<br>
   case DeclarationName::Identifier: {<br>
     const IdentifierInfo *II = Name.getAsIdentifierInfo();<br>
<br>
-    // We mangle decomposition declarations as the name of their first binding.<br>
+    // We mangle decomposition declarations as the names of their bindings.<br>
     if (auto *DD = dyn_cast<DecompositionDecl>(ND)) {<br>
-      auto B = DD->bindings();<br>
-      if (B.begin() == B.end()) {<br>
-        // FIXME: This is ill-formed but we accept it as an extension.<br>
-        DiagnosticsEngine &Diags = Context.getDiags();<br>
-        unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,<br>
-            "cannot mangle global empty decomposition decl");<br>
-        Diags.Report(DD->getLocation(), DiagID);<br>
-        break;<br>
-      }<br>
-      II = (*B.begin())->getIdentifier();<br>
+      // FIXME: Non-standard mangling for decomposition declarations:<br>
+      //<br>
+      //  <unqualified-name> ::= DC <source-name>* E<br>
+      //<br>
+      // These can never be referenced across translation units, so we do<br>
+      // not need a cross-vendor mangling for anything other than demanglers.<br>
+      // Proposed on cxx-abi-dev on 2016-08-12<br>
+      Out << "DC";<br>
+      for (auto *BD : DD->bindings())<br>
+        mangleSourceName(BD->getDeclName().getAsIdentifierInfo());<br>
+      Out << 'E';<br>
+      writeAbiTags(ND, AdditionalAbiTags);<br>
+      break;<br>
     }<br>
<br>
     if (II) {<br>
<br>
Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)<br>
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Sun Aug 14 20:33:41 2016<br>
@@ -394,7 +394,8 @@ bool MicrosoftMangleContextImpl::shouldM<br>
   if (!getASTContext().getLangOpts().CPlusPlus)<br>
     return false;<br>
<br>
-  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {<br>
+  const VarDecl *VD = dyn_cast<VarDecl>(D);<br>
+  if (VD && !isa<DecompositionDecl>(D)) {<br>
     // C variables are not mangled.<br>
     if (VD->isExternC())<br>
       return false;<br>
@@ -780,6 +781,21 @@ void MicrosoftCXXNameMangler::mangleUnqu<br>
         }<br>
       }<br>
<br>
+      if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(ND)) {<br>
+        // FIXME: Invented mangling for decomposition declarations:<br>
+        //   [X,Y,Z]<br>
+        // where X,Y,Z are the names of the bindings.<br>
+        llvm::SmallString<128> Name("[");<br>
+        for (auto *BD : DD->bindings()) {<br>
+          if (Name.size() > 1)<br>
+            Name += ',';<br>
+          Name += BD->getDeclName().getAsIdentifierInfo()->getName();<br>
+        }<br>
+        Name += ']';<br>
+        mangleSourceName(Name);<br>
+        break;<br>
+      }<br>
+<br>
       if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {<br>
         // We must have an anonymous union or struct declaration.<br>
         const CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl();<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sun Aug 14 20:33:41 2016<br>
@@ -87,6 +87,7 @@ void CodeGenFunction::EmitDecl(const Dec<br>
   case Decl::UsingShadow:<br>
   case Decl::ConstructorUsingShadow:<br>
   case Decl::ObjCTypeParam:<br>
+  case Decl::Binding:<br>
     llvm_unreachable("Declaration should not be in declstmts!");<br>
   case Decl::Function:  // void X();<br>
   case Decl::Record:    // struct/union/class X;<br>
@@ -119,10 +120,13 @@ void CodeGenFunction::EmitDecl(const Dec<br>
     const VarDecl &VD = cast<VarDecl>(D);<br>
     assert(VD.isLocalVarDecl() &&<br>
            "Should not see file-scope variables inside a function!");<br>
-    return EmitVarDecl(VD);<br>
+    EmitVarDecl(VD);<br>
+    if (auto *DD = dyn_cast<DecompositionDecl>(&VD))<br>
+      for (auto *B : DD->bindings())<br>
+        if (auto *HD = B->getHoldingVar())<br>
+          EmitVarDecl(*HD);<br>
+    return;<br>
   }<br>
-  case Decl::Binding:<br>
-    return CGM.ErrorUnsupported(&D, "structured binding");<br>
<br>
   case Decl::OMPDeclareReduction:<br>
     return CGM.EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(&D), this);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Aug 14 20:33:41 2016<br>
@@ -2206,6 +2206,12 @@ LValue CodeGenFunction::EmitDeclRefLValu<br>
   if (const auto *FD = dyn_cast<FunctionDecl>(ND))<br>
     return EmitFunctionDeclLValue(*this, E, FD);<br>
<br>
+  // FIXME: While we're emitting a binding from an enclosing scope, all other<br>
+  // DeclRefExprs we see should be implicitly treated as if they also refer to<br>
+  // an enclosing scope.<br>
+  if (const auto *BD = dyn_cast<BindingDecl>(ND))<br>
+    return EmitLValue(BD->getBinding());<br>
+<br>
   llvm_unreachable("Unhandled DeclRefExpr");<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sun Aug 14 20:33:41 2016<br>
@@ -3772,6 +3772,10 @@ void CodeGenModule::EmitTopLevelDecl(Dec<br>
       return;<br>
   case Decl::VarTemplateSpecialization:<br>
     EmitGlobal(cast<VarDecl>(D));<br>
+    if (auto *DD = dyn_cast<DecompositionDecl>(D))<br>
+      for (auto *B : DD->bindings())<br>
+        if (auto *HD = B->getHoldingVar())<br>
+          EmitGlobal(HD);<br>
     break;<br>
<br>
   // Indirect fields from global anonymous structs and unions can be<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Aug 14 20:33:41 2016<br>
@@ -1160,6 +1160,7 @@ static bool checkTupleLikeDecomposition(<br>
     RefVD->setImplicit();<br>
     if (Src->isInlineSpecified())<br>
       RefVD->setInlineSpecified();<br>
+    RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD);<br>
<br>
     InitializedEntity Entity = InitializedEntity::InitializeBinding(RefVD);<br>
     InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc);<br>
@@ -1167,11 +1168,12 @@ static bool checkTupleLikeDecomposition(<br>
     E = Seq.Perform(S, Entity, Kind, Init);<br>
     if (E.isInvalid())<br>
       return true;<br>
+    E = S.ActOnFinishFullExpr(E.get(), Loc);<br>
+    if (E.isInvalid())<br>
+      return true;<br>
     RefVD->setInit(E.get());<br>
     RefVD->checkInitIsICE();<br>
<br>
-    RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD);<br>
-<br>
     E = S.BuildDeclarationNameExpr(CXXScopeSpec(),<br>
                                    DeclarationNameInfo(B->getDeclName(), Loc),<br>
                                    RefVD);<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp?rev=278642&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp?rev=278642&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp Sun Aug 14 20:33:41 2016<br>
@@ -0,0 +1,118 @@<br>
+// RUN: %clang_cc1 -std=c++1z -emit-llvm -o - %s | FileCheck %s<br>
+<br>
+namespace std {<br>
+  using size_t = decltype(sizeof(0));<br>
+  template<typename> struct tuple_size;<br>
+  template<size_t, typename> struct tuple_element;<br>
+}<br>
+<br>
+struct Y { int n; };<br>
+struct X { X(); X(Y); X(const X&); ~X(); };<br>
+<br>
+struct A { int a : 13; bool b; };<br>
+<br>
+struct B {};<br>
+template<> struct std::tuple_size<B> { enum { value = 2 }; };<br>
+template<> struct std::tuple_element<0,B> { using type = X; };<br>
+template<> struct std::tuple_element<1,B> { using type = const int&; };<br>
+template<int N> auto get(B) {<br>
+  if constexpr (N == 0)<br>
+    return Y();<br>
+  else<br>
+    return 0.0;<br>
+}<br>
+<br>
+using C = int[2];<br>
+<br>
+typedef int D __attribute__((ext_vector_type(2)));<br>
+<br>
+using E = _Complex int;<br>
+<br>
+template<typename T> T &make();<br>
+<br>
+// CHECK: @_ZDC2a12a2E = global {{.*}} zeroinitializer, align 4<br>
+auto [a1, a2] = make<A>();<br>
+// CHECK: @_ZDC2b12b2E = global {{.*}} zeroinitializer, align 1<br>
+// CHECK: @b1 = global {{.*}}* null, align 8<br>
+// CHECK: @_ZGR2b1_ = internal global {{.*}} zeroinitializer, align 1<br>
+// CHECK: @b2 = global i32* null, align 8<br>
+// CHECK: @_ZGR2b2_ = internal global i32 0, align 4<br>
+auto [b1, b2] = make<B>();<br>
+// CHECK: @_ZDC2c12c2E = global [2 x i32]* null, align 8<br>
+auto &[c1, c2] = make<C>();<br>
+// CHECK: @_ZDC2d12d2E = global <2 x i32> zeroinitializer, align 8<br>
+auto [d1, d2] = make<D>();<br>
+// CHECK: @_ZDC2e12e2E = global { i32, i32 } zeroinitializer, align 4<br>
+auto [e1, e2] = make<E>();<br>
+<br>
+// CHECK: call {{.*}}* @_Z4makeI1AERT_v()<br>
+// CHECK: call {{.*}}memcpy{{.*}}@_ZDC2a12a2E<br>
+<br>
+// CHECK: @_Z4makeI1BERT_v()<br>
+//   CHECK: call i32 @_Z3getILi0EEDa1B()<br>
+//   CHECK: call void @_ZN1XC1E1Y({{.*}}* @_ZGR2b1_, i32<br>
+//   CHECK: call i32 @__cxa_atexit({{.*}}@_ZN1XD1Ev{{.*}}@_ZGR2b1_<br>
+//   CHECK: store {{.*}}* @_ZGR2b1_,<br>
+//<br>
+//   CHECK: call double @_Z3getILi1EEDa1B()<br>
+//   CHECK: fptosi double %{{.*}} to i32<br>
+//   CHECK: store i32 %{{.*}}, i32* @_ZGR2b2_<br>
+//   CHECK: store i32* @_ZGR2b2_, i32** @b2<br>
+<br>
+// CHECK: call {{.*}}* @_Z4makeIA2_iERT_v()<br>
+// CHECK: store {{.*}}, [2 x i32]** @_ZDC2c12c2E<br>
+<br>
+// CHECK: call {{.*}}* @_Z4makeIDv2_iERT_v()<br>
+// CHECK: store {{.*}}, <2 x i32>* @_ZDC2d12d2E, align 8<br>
+<br>
+// CHECK: call {{.*}}* @_Z4makeICiERT_v()<br>
+// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_ZDC2e12e2E, i32 0, i32 0)<br>
+// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_ZDC2e12e2E, i32 0, i32 1)<br>
+<br>
+// CHECK: define i32 @_Z12test_globalsv()<br>
+int test_globals() {<br>
+  return a2 + b2 + c2 + d2 + e2;<br>
+  // CHECK: load i8, i8* getelementptr inbounds (%struct.A, %struct.A* @_ZDC2a12a2E, i32 0, i32 1)<br>
+  //<br>
+  // CHECK: %[[b2:.*]] = load i32*, i32** @b2<br>
+  // CHECK: load i32, i32* %[[b2]]<br>
+  //<br>
+  // CHECK: %[[c1c2:.*]] = load [2 x i32]*, [2 x i32]** @_ZDC2c12c2E<br>
+  // CHECK: %[[c2:.*]] = getelementptr inbounds [2 x i32], [2 x i32]* %[[c1c2]], i64 0, i64 1<br>
+  // CHECK: load i32, i32* %[[c2]]<br>
+  //<br>
+  // CHECK: %[[d1d2:.*]] = load <2 x i32>, <2 x i32>* @_ZDC2d12d2E<br>
+  // CHECK: extractelement <2 x i32> %[[d1d2]], i32 1<br>
+  //<br>
+  // CHECK: load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_ZDC2e12e2E, i32 0, i32 1)<br>
+}<br>
+<br>
+// CHECK: define i32 @_Z11test_localsv()<br>
+int test_locals() {<br>
+  auto [b1, b2] = make<B>();<br>
+<br>
+  // CHECK: @_Z4makeI1BERT_v()<br>
+  //   CHECK: call i32 @_Z3getILi0EEDa1B()<br>
+  //   CHECK: call void @_ZN1XC1E1Y({{.*}}* %[[b1:.*]], i32<br>
+  //<br>
+  //   CHECK: call double @_Z3getILi1EEDa1B()<br>
+  //   CHECK: %[[cvt:.*]] = fptosi double %{{.*}} to i32<br>
+  //   CHECK: store i32 %[[cvt]], i32* %[[b2:.*]],<br>
+  //   CHECK: store i32* %[[b2]], i32** %[[b2ref:.*]],<br>
+<br>
+  return b2;<br>
+  // CHECK: %[[b2:.*]] = load i32*, i32** %[[b2ref]]<br>
+  // CHECK: load i32, i32* %[[b2]]<br>
+<br>
+  // CHECK: call {{.*}}@_ZN1XD1Ev({{.*}}%[[b1]])<br>
+}<br>
+<br>
+// CHECK: define void @_Z13test_bitfieldR1A(<br>
+void test_bitfield(A &a) {<br>
+  auto &[a1, a2] = a;<br>
+  a1 = 5;<br>
+  // CHECK: load i16, i16* %[[BITFIELD:.*]],<br>
+  // CHECK: and i16 %{{.*}}, -8192<br>
+  // CHECK: or i16 %{{.*}}, 5<br>
+  // CHECK: store i16 %{{.*}}, i16* %[[BITFIELD]],<br>
+}<br>
<br>
Modified: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=278642&r1=278641&r2=278642&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=278642&r1=278641&r2=278642&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Sun Aug 14 20:33:41 2016<br>
@@ -38,4 +38,3 @@ constexpr bool g(S &&s) {<br>
 static_assert(g({1, 2}));<br>
<br>
 // FIXME: by-value array copies<br>
-// FIXME: code generation<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>