`self` clauses on compute constructs take an optional condition expression. We again limit the implementation to ONLY compute constructs to ensure we get all the rules correct for others. However, this one will be particularly complicated, as it takes a `var-list` for `update`, so when we get to that construct/clause combination, we need to do that as well. This patch also furthers uses of the `OpenACCClauses.def` as it became useful while implementing this (as well as some other minor refactors as I went through). Finally, `self` and `if` clauses have an interaction with each other, if an `if` clause evaluates to `true`, the `self` clause has no effect. While this is intended and can be used 'meaningfully', we are warning on this with a very granular warning, so that this edge case will be noticed by newer users, but can be disabled trivially.
100 lines
3.7 KiB
C++
100 lines
3.7 KiB
C++
// RUN: %clang_cc1 %s -fopenacc -verify
|
|
|
|
struct NoBoolConversion{};
|
|
struct BoolConversion{
|
|
operator bool();
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
void BoolExpr() {
|
|
// expected-error@+1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
|
|
#pragma acc parallel self (NoBoolConversion{})
|
|
while(0);
|
|
// expected-error@+2{{no member named 'NotValid' in 'NoBoolConversion'}}
|
|
// expected-note@#INST{{in instantiation of function template specialization}}
|
|
#pragma acc parallel self (T::NotValid)
|
|
while(0);
|
|
|
|
#pragma acc parallel self (BoolConversion{})
|
|
while(0);
|
|
|
|
// expected-error@+1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
|
|
#pragma acc parallel self (T{})
|
|
while(0);
|
|
|
|
#pragma acc parallel self (U{})
|
|
while(0);
|
|
}
|
|
|
|
struct HasBool {
|
|
static constexpr bool B = true;
|
|
};
|
|
|
|
template<typename T>
|
|
void WarnMaybeNotUsed() {
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel self if(T::B)
|
|
while(0);
|
|
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel self(T::B) if(T::B)
|
|
while(0);
|
|
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel if(T::B) self
|
|
while(0);
|
|
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel if(T::B) self(T::B)
|
|
while(0);
|
|
|
|
// We still warn in the cases of dependent failures, since the diagnostic
|
|
// happens immediately rather than during instantiation.
|
|
|
|
// expected-error@+4{{no member named 'Invalid' in 'HasBool'}}
|
|
// expected-note@#NOT_USED_INST{{in instantiation of function template specialization 'WarnMaybeNotUsed<HasBool>' requested here}}
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel self if(T::Invalid)
|
|
while(0);
|
|
|
|
// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel self(T::Invalid) if(T::B)
|
|
while(0);
|
|
|
|
// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel self(T::B) if(T::Invalid)
|
|
while(0);
|
|
|
|
// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel if(T::Invalid) self
|
|
while(0);
|
|
|
|
// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel if(T::Invalid) self(T::B)
|
|
while(0);
|
|
|
|
// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
|
|
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
|
|
// expected-note@+1{{previous clause is here}}
|
|
#pragma acc parallel if(T::B) self(T::Invalid)
|
|
while(0);
|
|
}
|
|
|
|
void Instantiate() {
|
|
BoolExpr<NoBoolConversion, BoolConversion>(); // #INST
|
|
WarnMaybeNotUsed<HasBool>(); // #NOT_USED_INST
|
|
}
|