llvm/clang/test/SemaOpenACC/sub-array.cpp

// RUN: %clang_cc1 %s -verify -fopenacc

struct Incomplete; // #INCOMPLETE
struct NotConvertible{} NC;

struct CorrectConvert {
  operator int();
} Convert;

constexpr int returns_3() { return 3; }

using FuncPtrTy = void (*)();
FuncPtrTy FuncPtrTyArray[2];

void Func(int i, int j) {
  int array[5];
  int VLA[i];
  int *ptr;
  void *void_ptr;

  // Follows int-expr rules, so only convertible to int.
  // expected-error@+1{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel private(array[NC:])
  while (true);

  // expected-error@+1{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel private(array[:NC])
  while (true);

  // expected-error@+2{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
  // expected-error@+1{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel private(array[NC:NC])
  while (true);

  // expected-error@+2{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
  // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}}
#pragma acc parallel private(ptr[NC:])
  while (true);

  // expected-error@+1{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel private(ptr[:NC])
  while (true);

  // expected-error@+2{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
  // expected-error@+1{{OpenACC sub-array bound requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel private(ptr[NC:NC])
  while (true);

  // These are convertible, so they work.
#pragma acc parallel private(array[Convert:Convert])
  while (true);

#pragma acc parallel private(ptr[Convert:Convert])
  while (true);


  // The length for "dynamically" allocated dimensions of an array must be
  // explicitly specified.

  // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}}
#pragma acc parallel private(ptr[3:])
  while (true);

  // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is an array of unknown bound}}
#pragma acc parallel private(VLA[3:])
  while (true);

#pragma acc parallel private(ptr[:3])
  while (true);

#pragma acc parallel private(VLA[:3])
  while (true);

  // Error if the length of the array + the initializer is bigger the the array
  // with known bounds.

  // expected-error@+1{{OpenACC sub-array length evaluated to a value (6) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(array[i:returns_3() + 3])
  while (true);

  // expected-error@+1{{OpenACC sub-array length evaluated to a value (6) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(array[:returns_3() + 3])
  while (true);

#pragma acc parallel private(array[:returns_3()])
  while (true);

  // expected-error@+1{{OpenACC sub-array specified range [3:3] would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(array[returns_3():returns_3()])
  while (true);

  // expected-error@+1{{OpenACC sub-array lower bound evaluated to a value (6) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(array[returns_3() + 3:])
  while (true);

  // expected-error@+1{{OpenACC sub-array lower bound evaluated to a value (6) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(array[returns_3() + 3:1])
  while (true);

  // Standard doesn't specify this, but negative values are likely not
  // permitted, so disallow them here until we come up with a good reason to do
  // otherwise.

  // expected-error@+1{{OpenACC sub-array lower bound evaluated to negative value -1}}
#pragma acc parallel private(array[returns_3() - 4 : ])
  while (true);

  // expected-error@+1{{OpenACC sub-array length evaluated to negative value -1}}
#pragma acc parallel private(array[: -1])
  while (true);

  Incomplete *IncompletePtr;
  // expected-error@+2{{OpenACC sub-array base is of incomplete type 'Incomplete'}}
  // expected-note@#INCOMPLETE{{forward declaration of 'Incomplete'}}
#pragma acc parallel private(IncompletePtr[0 :1])
  while (true);

  // expected-error@+1{{OpenACC sub-array base is of incomplete type 'void'}}
#pragma acc parallel private(void_ptr[0:1])
  while (true);

  // OK: these are function pointers.
#pragma acc parallel private(FuncPtrTyArray[0 :1])
  while (true);

  // expected-error@+1{{OpenACC sub-array cannot be of function type 'void ()'}}
#pragma acc parallel private(FuncPtrTyArray[0][0 :1])
  while (true);


  // expected-error@+1{{OpenACC sub-array subscripted value is not an array or pointer}}
#pragma acc parallel private(i[0:1])
  while (true);
}

template<typename T, typename U, typename V, unsigned I, auto &CEArray>
void Templ(int i){
  T array[I];
  T VLA[i];
  T *ptr;
  U NC;
  V Conv;

  // Convertible:
  // expected-error@+2{{OpenACC sub-array bound requires expression of integer type ('NotConvertible' invalid}}
  // expected-note@#INST{{in instantiation of function template specialization}}
#pragma acc parallel private(array[NC:])
  while (true);
  // expected-error@+1{{OpenACC sub-array bound requires expression of integer type ('NotConvertible' invalid}}
#pragma acc parallel private(array[:NC])
  while (true);

#pragma acc parallel private(array[Conv:])
  while (true);
#pragma acc parallel private(array[:Conv])
  while (true);

  // Need a length for unknown size.
  // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}}
#pragma acc parallel private(ptr[Conv:])
  while (true);
  // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is an array of unknown bound}}
#pragma acc parallel private(VLA[Conv:])
  while (true);
#pragma acc parallel private(ptr[:Conv])
  while (true);
#pragma acc parallel private(VLA[:Conv])
  while (true);

  // Out of bounds.
  // expected-error@+1{{OpenACC sub-array lower bound evaluated to a value (2) that would be out of the range of the subscripted array size of 2}}
#pragma acc parallel private(array[I:])
  while (true);

  // OK, don't know the value.
#pragma acc parallel private(array[i:])
  while (true);

  // expected-error@+1{{OpenACC sub-array length evaluated to a value (3) that would be out of the range of the subscripted array size of 2}}
#pragma acc parallel private(array[:I + 1])
  while (true);

  // expected-error@+1{{OpenACC sub-array lower bound evaluated to a value (5) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(CEArray[5:])
  while (true);

  // expected-error@+1{{OpenACC sub-array length evaluated to a value (6) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(CEArray[:2 + I + I])
  while (true);

  // expected-error@+1{{OpenACC sub-array length evaluated to a value (4294967295) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(CEArray[:1 - I])
  while (true);

  // expected-error@+1{{OpenACC sub-array lower bound evaluated to a value (4294967295) that would be out of the range of the subscripted array size of 5}}
#pragma acc parallel private(CEArray[1 - I:])
  while (true);

  T not_ptr;
  // expected-error@+1{{OpenACC sub-array subscripted value is not an array or pointer}}
#pragma acc parallel private(not_ptr[0:1])
  while (true);
}

void inst() {
  static constexpr int CEArray[5]={1,2,3,4,5};
  Templ<int, NotConvertible, CorrectConvert, 2, CEArray>(5); // #INST
}