extern "C" void abort (); struct S { char a[64]; int (&r)[2]; char b[64]; }; __attribute__((noinline, noclone)) void foo (S s, int (&t)[3], int z) { int err, sep = 1; // Test that implicit mapping of reference to array does NOT // behave like zero length array sections. s.r can't be used // implicitly, as that means implicit mapping of the whole s // and trying to dereference the references in there is unspecified. #pragma omp target map(from: err) map(to: sep) { err = t[0] != 1 || t[1] != 2 || t[2] != 3; sep = 0; } if (err) abort (); // But explicit zero length array section mapping does. #pragma omp target map(from: err) map(tofrom: s.r[:0], t[:0]) { if (sep) err = s.r != (int *) 0 || t != (int *) 0; else err = t[0] != 1 || t[1] != 2 || t[2] != 3 || s.r[0] != 6 || s.r[1] != 7; } if (err) abort (); // Similarly zero length array section, but unknown at compile time. #pragma omp target map(from: err) map(tofrom: s.r[:z], t[:z]) { if (sep) err = s.r != (int *) 0 || t != (int *) 0; else err = t[0] != 1 || t[1] != 2 || t[2] != 3 || s.r[0] != 6 || s.r[1] != 7; } if (err) abort (); #pragma omp target enter data map (to: s.r, t) // But when already mapped, it binds to existing mappings. #pragma omp target map(from: err) map(tofrom: s.r[:0], t[:0]) { err = t[0] != 1 || t[1] != 2 || t[2] != 3 || s.r[0] != 6 || s.r[1] != 7; sep = 0; } if (err) abort (); #pragma omp target map(from: err) map(tofrom: s.r[:z], t[:z]) { err = t[0] != 1 || t[1] != 2 || t[2] != 3 || s.r[0] != 6 || s.r[1] != 7; sep = 0; } if (err) abort (); } int main () { int t[3] = { 1, 2, 3 }; int r[2] = { 6, 7 }; S s = { {}, r, {} }; foo (s, t, 0); }