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
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp (revision 203417)
+++ lib/AST/ItaniumMangle.cpp (working copy)
@@ -445,6 +445,8 @@
mangleName(cast<FieldDecl>(D));
}
+static bool IsNotEnableIfAttr(Attr *A) { return !isa<EnableIfAttr>(A); }
+
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <encoding> ::= <function name> <bare-function-type>
mangleName(FD);
@@ -453,6 +455,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.
+ AttrVec Attrs = FD->getAttrs();
+ AttrVec::iterator E = std::remove_if(Attrs.begin(), Attrs.end(),
+ IsNotEnableIfAttr);
+ std::reverse(Attrs.begin(), E);
+ for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) {
+ EnableIfAttr *EIA = cast<EnableIfAttr>(*I);
+ 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 (working copy)
@@ -0,0 +1,12 @@
+// 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, ""))) {}
Index: src/cxa_demangle.cpp
===================================================================
--- src/cxa_demangle.cpp (revision 203370)
+++ src/cxa_demangle.cpp (working copy)
@@ -4449,7 +4449,55 @@
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>
@@ -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
Index: test/test_demangle.cpp
===================================================================
--- test/test_demangle.cpp (revision 203370)
+++ test/test_demangle.cpp (working copy)
@@ -29586,6 +29586,14 @@
{"_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)"},
+
+ {"_Z4testUa8noreturn", "test __attribute__((noreturn))"},
+ {"_Z4testUa8noreturnv", "test() __attribute__((noreturn))"},
+ {"_Z5test1Ua9enable_ifIXeqfL0p_Li1EEEi", "test1(int) __attribute__(((fp) == (1))))"},
+ // FIXME: should be '&ext' not '&(ext())'
+ {"_Z5test2Ua9enable_ifIXneadL_Z3extvELi0EEEi", "test2(int) __attribute__((enable_if((&(ext())) != (0))))"},
+ {"_Z5test3Ua9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEii", "test3(int, int) __attribute__((enable_if((fp) == (1), (fp0) == (2))))"},
+ {"_Z5test4Ua5attr1Ua5attr2IEUa5attr3IXLi1EEEUa5attr4IXLi1EEXLi2EEE", "test4 __attribute__((attr1)) __attribute__((attr2())) __attribute__((attr3(1))) __attribute__((attr4(1, 2)))"},
};
const unsigned N = sizeof(cases) / sizeof(cases[0]);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits