[LLVMbugs] [Bug 19025] New: invalid merging of two template variables

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Sun Mar 2 06:32:10 PST 2014


http://llvm.org/bugs/show_bug.cgi?id=19025

            Bug ID: 19025
           Summary: invalid merging of two template variables
           Product: clang
           Version: trunk
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++1y
          Assignee: unassignedclangbugs at nondot.org
          Reporter: galopin at gmail.com
                CC: llvmbugs at cs.uiuc.edu
    Classification: Unclassified

Created attachment 12175
  --> http://llvm.org/bugs/attachment.cgi?id=12175&action=edit
the two source file and a batch to build with clang-cl

The attached code try to convert constexpr arrays of enum classes values to
arrays of their underlying type.

The arrays are then accessed with template variables.

When arrays are indexed, if it is in a template function on the enum type, the
compiler mess with the arrays and use for each template instantiation the first
encountered one. If the functions are not template, every thing is ok.

I have the following functions ( E1 and E2 are enum class, and baz is the
template variable ) :

template <typename T> int read(int i) { return baz<T> [i]; }
int array1(int i) { return read<E1>(i); }
int array2(int i) { return read<E2>(i); }

constexpr auto const tab1 = baz<E1>;
constexpr auto const tab2 = baz<E2>;
int array1b(int i) { return tab1[i]; }
int array2b(int i) { return tab2[i]; }

They are called in the main function to dump the arrays 
for (int i{}; i != 3; ++i)
        std::cout << array1(i) << " ";
for (int i{}; i != 3; ++i)
        std::cout << array2(i) << " ";
std::cout << std::endl;
for (int i{}; i != 3; ++i)
    std::cout << array1b(i) << " ";
for (int i{}; i != 3; ++i)
    std::cout << array2b(i) << " ";

The output should be :
0 1 2 3 4 5
0 1 2 3 4 5
But it is :
3 4 5 3 4 5
0 1 2 3 4 5

If array1 and array2 definition is swapped, the first line will be "0 1 2 0 1
2" instead.

The remaining code to generate the arrays ( do not use std::array as it lacks
constexpr operator[] ):

template <typename T_, size_t N_> struct Array {
    constexpr size_t size() const { return N_; }
    constexpr bool empty() const { return N_ == 0; }

    constexpr T_ &operator[](size_t i) { return values_[i]; }
    constexpr T_ const &operator[](size_t i) const { return values_[i]; }

    constexpr T_ *begin() { return values_; }
    constexpr T_ *end() { return values_ + N_; }
    constexpr T_ const *begin() const { return values_; }
    constexpr T_ const *end() const { return values_ + N_; }

    T_ values_[N_];
};

enum class E1 { a = 0, b, c };
enum class E2 { a = 3, b, c };

template <typename E_> constexpr auto foo();

template <> constexpr auto foo<E1>() {
    return Array<E1, 4>{{E1::a, E1::b, E1::c}};
}
template <> constexpr auto foo<E2>() {
    return Array<E2, 4>{{E2::a, E2::b, E2::c}};
}

template <typename E_, size_t N_> constexpr auto ToIntArray(Array<E_, N_> const
&tab) {
    Array<std::underlying_type_t<E_>, N_> result{};
    for (size_t i{}; i != N_; ++i)
        result[i] = std::underlying_type_t<E_>(tab[i]);
    return result;
}

template <typename T_> constexpr decltype(foo<T_>()) bar = foo<T_>();
template <typename T_> constexpr decltype(ToIntArray(bar<T_>)) baz =
ToIntArray(bar<T_>);

Clang is built with the trunk of 20140302 with VS2013 :
clang version 3.5 (202633)
Target: x86_64-pc-win32
Thread model: posix

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20140302/f95f7ccf/attachment.html>


More information about the llvm-bugs mailing list