On 9 March 2014 17:10, Richard Smith <[email protected]> wrote:

> Your lambda doesn't capture anything -- maybe use [] rather than [&]?
> (Maybe we should warn on this.)
>
> Maybe use a reverse_iterator loop over FD->getAttrs, and skip the
> non-EnableIfAttrs. That'd remove the need to make a copy of the vector and
> to reverse it. (Do we have llvm::reversed yet? If so, 'for (Attr *A :
> reversed(FD->getAttrs()))' seems like a nice way to write this.)
>

Done.

Updated patches attached, please review.

Nick


> On Sun, Mar 9, 2014 at 5:02 PM, Nick Lewycky <[email protected]> wrote:
>
>> On 03/09/2014 11:01 AM, David Majnemer wrote:
>>
>>> Your std::remove_if would be more concise if it used a lambda instead
>>> of IsNotEnableIfAttr.
>>>
>>
>> Done. Also added another test case to the mangling tests.
>>
>> Nick
>>
>>  On Sun Mar 09 2014 at 10:30:45 AM, Nick Lewycky <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>>     The attached mangle-enable_if-1.patch adds a mangling for
>>>     __attribute__((enable_if(expr, string-literal))) to clang.
>>>
>>>     demangle-enable_if-1.patch adds support to libcxxabi's demangler.
>>> This
>>>     patch I'm not very confident in. libcxxabi's cxa_demangle lacks
>>> comments
>>>     and assertions, leaving its design criteria a mystery. I think the
>>>     functions return 'first' in case of error. I added a vector<> inside
>>> the
>>>     demangler, I don't know whether that's OK because it means doing
>>>     allocation. I don't know what the two strings in the pair in db.names
>>>     are for, but the first one appears to be the demangling so I put it
>>>     there. I don't understand what the members in 'db' are for, since
>>> they
>>>     aren't commented (db.tag_templates?). The code is cargo culted from
>>>     parse_template_args and simplified down by making wild assumptions
>>>     (db.tag_templates is always false!) and constant folding.
>>>
>>>     Also the demangler seems pretty buggy. It wraps expressions in extra
>>>     parentheses which don't correspond to pi .. E expressions (if you
>>> were
>>>     to remangle it, you'd get the extra pi .. E). A mangling for
>>> "&function"
>>>     ends up demangling "&(function())" which has different semantic
>>> meaning.
>>>        I'm assuming these problems are pre-existing. While "_Z3foo"
>>>     demangles
>>>     to "foo" and "_Z3foov" demangles to "foo()", the same things with an
>>>     attribute demangle to include parens. For example, "_Z3fooUa3bar" and
>>>     "_Z3fooUa3barv" both demangle to "foo() __attribute__((bar))", never
>>>     "foo __attribute__((bar))".
>>>
>>>     Finally, I've never even compiled the change to the tests. I have
>>> tested
>>>     those exact manglings and seen what cxa_demangle does to them, but it
>>>     was easier to write a standalone tool than to deal with "testit".
>>>
>>>     Please review!
>>>
>>>     Nick
>>>     _________________________________________________
>>>     cfe-commits mailing list
>>>     [email protected] <mailto:[email protected]>
>>>     http://lists.cs.uiuc.edu/__mailman/listinfo/cfe-commits
>>>     <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits>
>>>
>>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> [email protected]
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>>
>
> _______________________________________________
> cfe-commits mailing list
> [email protected]
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>
Index: src/cxa_demangle.cpp
===================================================================
--- src/cxa_demangle.cpp	(revision 207151)
+++ src/cxa_demangle.cpp	(working copy)
@@ -4449,10 +4449,58 @@
     save_value& operator=(const save_value&) = delete;
 };
 
-// <encoding> ::= <function name> <bare-function-type>
+// <attribute> ::= Ua <source-name> [ <template-args> ]
+template <class C>
+const char*
+parse_attribute(const char* first, const char* last, C& db) {
+    if (first != last)
+    {
+        const char* t = parse_source_name(first, last, db);
+        if (t != first)
+        {
+            db.names.back().first = "__attribute__((" + db.names.back().first;
+            const char* t1 = t;
+            if (last - t >= 2 && *t == 'I') {
+                ++t1;
+                typename C::String args("(");
+                while (*t1 != 'E')
+                {
+                    db.template_param.emplace_back(db.names.get_allocator());
+                    size_t k0 = db.names.size();
+                    const char* t2 = parse_template_arg(t1, last, db);
+                    size_t k1 = db.names.size();
+                    db.template_param.pop_back();
+                    if (t2 == t1 || t2 == last)
+                        return first;
+                    db.template_param.back().emplace_back(db.names.get_allocator());
+                    for (size_t k = k0; k < k1; ++k)
+                    {
+                        if (args.size() > 1)
+                            args += ", ";
+                        args += db.names[k].move_full();
+                    }
+                    for (; k1 != k0; --k1)
+                        db.names.pop_back();
+                    t1 = t2;
+                    t = t1 + 1;
+                }
+                args += ')';
+                db.names.back().first += std::move(args);
+                if (*t1 != 'E')
+                    return first;
+                ++t1;
+            }
+            db.names.back().first += "))";
+            first = t1;
+        }
+    }
+    return first;
+}
+
+// <encoding> ::= <function name> <attribute>* <bare-function-type>
 //            ::= <data name>
 //            ::= <special-name>
-
+//  extension ::= <function name> <bare-function-type> <attribute>+
 template <class C>
 const char*
 parse_encoding(const char* first, const char* last, C& db)
@@ -4488,6 +4536,13 @@
                     const typename C::String& nm = db.names.back().first;
                     if (nm.empty())
                         return first;
+                    std::vector<typename C::String> attributes;
+                    while (t != last && *t == 'U' && (t+1) != last && t[1] == 'a') {
+                        t += 2;
+                        t = parse_attribute(t, last, db);
+                        attributes.push_back(db.names.back().first);
+                        db.names.pop_back();
+                    }
                     if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
                                                                     && nm[nm.size()-2] != '>')
                     {
@@ -4544,8 +4599,13 @@
                             t = t2;
                         }
                     }
-                    if (db.names.empty())
+                    if (db.names.empty()) {
+                        for (auto& attr : attributes) {
+                            db.names.back().first.append(" ");
+                            db.names.back().first.append(attr);
+                        }
                         return first;
+                    }
                     db.names.back().first += ')';
                     if (cv & 1)
                         db.names.back().first.append(" const");
@@ -4558,6 +4618,10 @@
                     else if (ref == 2)
                         db.names.back().first.append(" &&");
                     db.names.back().first += ret2;
+                    for (auto& attr : attributes) {
+                        db.names.back().first.append(" ");
+                        db.names.back().first.append(attr);
+                    }
                     first = t;
                 }
                 else
@@ -4625,6 +4689,43 @@
     return first;
 }
 
+// extension
+// <attributes> := <attribute>*
+// <attribute> := Ua <source-name> <template-args>
+
+template <class C>
+const char*
+parse_attributes(const char* first, const char* last, C& db)
+{
+    print_state("before", first, last, db);
+    while (first != last && first + 1 != last &&
+           first[0] == 'U' && first[1] == 'a')
+    {
+        const char* t = parse_source_name(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_template_args(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto args = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first = " __attribute__((" + db.names.back().first + std::move(args) + "))";
+                args = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first += args;
+            }
+            first = t1;
+        }
+        else
+            first = t;
+    }
+    print_state("after", first, last, db);
+    return first;
+}
+
+
 // <block-involcaton-function> ___Z<encoding>_block_invoke
 // <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
 // <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
@@ -4649,6 +4750,8 @@
                 const char* t = parse_encoding(first+2, last, db);
                 if (t != first+2 && t != last && *t == '.')
                     t = parse_dot_suffix(t, last, db);
+                if (t != first+2 && t != last && t[0] == 'U' && t[1] == 'a')
+                    t = parse_attributes(t, last, db);
                 if (t != last)
                     status = invalid_mangled_name;
             }
Index: test/test_demangle.cpp
===================================================================
--- test/test_demangle.cpp	(revision 207151)
+++ test/test_demangle.cpp	(working copy)
@@ -29586,6 +29586,16 @@
     {"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_", "decltype(-[DeploymentSetupController handleManualServerEntry:]::$_5& Ncr::Silver::Utility::detail::getT<-[DeploymentSetupController handleManualServerEntry:]::$_5>()()(std::forward<-[DeploymentSetupController handleManualServerEntry:]::$_5>(fp))) Ncr::Silver::Utility::detail::CallOnThread<-[DeploymentSetupController handleManualServerEntry:]::$_5>::operator()<>(-[DeploymentSetupController handleManualServerEntry:]::$_5&&) const"},
     {"_Zli2_xy", "operator\"\" _x(unsigned long long)"},
     {"_Z1fIiEDcT_", "decltype(auto) f<int>(int)"},
+
+    // FIXME: should be 'test' not 'test()'
+    {"_Z4testUa8noreturn", "test() __attribute__((noreturn))"},
+    // FIXME: should be '&ext' not '&(ext())'
+    {"_Z5test2Ua9enable_ifIXneadL_Z3extvELi0EEEi", "test2(int) __attribute__((enable_if((&(ext())) != (0))))"},
+
+    {"_Z4testUa8noreturnv", "test() __attribute__((noreturn))"},
+    {"_Z5test1Ua9enable_ifIXeqfL0p_Li1EEEi", "test1(int) __attribute__((enable_if((fp) == (1))))"},
+    {"_Z5test3Ua9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEii", "test3(int, int) __attribute__((enable_if((fp) == (1), (fp0) == (2))))"},
+    {"_Z5test4Ua5attr1Ua5attr2IEUa5attr3IXLi1EEEUa5attr4IXLi1EEXLi2EEEv", "test4() __attribute__((attr1)) __attribute__((attr2())) __attribute__((attr3(1))) __attribute__((attr4(1, 2)))"},
 };
 
 const unsigned N = sizeof(cases) / sizeof(cases[0]);
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp	(revision 207151)
+++ lib/AST/ItaniumMangle.cpp	(working copy)
@@ -456,6 +456,25 @@
   if (!Context.shouldMangleDeclName(FD))
     return;
 
+  if (FD->hasAttr<EnableIfAttr>()) {
+    FunctionTypeDepthState saved = FunctionTypeDepth.push();
+    Out << "Ua9enable_ifI";
+    // FIXME: specific_attr_iterator iterates in reverse order. Fix that and use
+    // it here.
+    for (AttrVec::const_reverse_iterator I = FD->getAttrs().rbegin(),
+                                         E = FD->getAttrs().rend();
+         I != E; ++I) {
+      EnableIfAttr *EIA = dyn_cast<EnableIfAttr>(*I);
+      if (!EIA)
+        continue;
+      Out << 'X';
+      mangleExpression(EIA->getCond());
+      Out << 'E';
+    }
+    Out << 'E';
+    FunctionTypeDepth.pop(saved);
+  }
+
   // Whether the mangling of a function type includes the return type depends on
   // the context and the nature of the function. The rules for deciding whether
   // the return type is included are:
Index: test/CodeGenCXX/enable_if.cpp
===================================================================
--- test/CodeGenCXX/enable_if.cpp	(revision 0)
+++ test/CodeGenCXX/enable_if.cpp	(revision 0)
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux-gnu| FileCheck %s
+// Test itanium mangling for attribute enable_if
+
+// CHECK: _Z5test1Ua9enable_ifIXeqfL0p_Li1EEEi
+void test1(int i) __attribute__((enable_if(i == 1, ""))) {}
+
+void ext();
+// CHECK: _Z5test2Ua9enable_ifIXneadL_Z3extvELi0EEEi
+void test2(int i) __attribute__((enable_if(&ext != 0, ""))) {}
+
+// CHECK: _Z5test3Ua9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEii
+void test3(int i, int j) __attribute__((enable_if(i == 1, ""), enable_if(j == 2, ""))) {}
+
+// CHECK: _ZN5test4IdE1fEUa9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEi
+template <typename T>
+class test4 {
+  virtual void f(int i, int j) __attribute__((enable_if(i == 1, ""))) __attribute__((enable_if(j == 2, "")));
+};
+
+template class test4<double>;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to