summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaOpenMP.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp167
1 files changed, 144 insertions, 23 deletions
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 0af38fb51c8..bc15c023142 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -9104,6 +9104,94 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
return true;
}
+/// \brief Return true if it can be proven that the provided array expression
+/// (array section or array subscript) does NOT specify the whole size of the
+/// array whose base type is \a BaseQTy.
+static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
+ const Expr *E,
+ QualType BaseQTy) {
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
+
+ // If this is an array subscript, it refers to the whole size if the size of
+ // the dimension is constant and equals 1. Also, an array section assumes the
+ // format of an array subscript if no colon is used.
+ if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) {
+ if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
+ return ATy->getSize().getSExtValue() != 1;
+ // Size can't be evaluated statically.
+ return false;
+ }
+
+ assert(OASE && "Expecting array section if not an array subscript.");
+ auto *LowerBound = OASE->getLowerBound();
+ auto *Length = OASE->getLength();
+
+ // If there is a lower bound that does not evaluates to zero, we are not
+ // convering the whole dimension.
+ if (LowerBound) {
+ llvm::APSInt ConstLowerBound;
+ if (!LowerBound->EvaluateAsInt(ConstLowerBound, SemaRef.getASTContext()))
+ return false; // Can't get the integer value as a constant.
+ if (ConstLowerBound.getSExtValue())
+ return true;
+ }
+
+ // If we don't have a length we covering the whole dimension.
+ if (!Length)
+ return false;
+
+ // If the base is a pointer, we don't have a way to get the size of the
+ // pointee.
+ if (BaseQTy->isPointerType())
+ return false;
+
+ // We can only check if the length is the same as the size of the dimension
+ // if we have a constant array.
+ auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr());
+ if (!CATy)
+ return false;
+
+ llvm::APSInt ConstLength;
+ if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext()))
+ return false; // Can't get the integer value as a constant.
+
+ return CATy->getSize().getSExtValue() != ConstLength.getSExtValue();
+}
+
+// Return true if it can be proven that the provided array expression (array
+// section or array subscript) does NOT specify a single element of the array
+// whose base type is \a BaseQTy.
+static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
+ const Expr *E,
+ QualType BaseQTy) {
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
+
+ // An array subscript always refer to a single element. Also, an array section
+ // assumes the format of an array subscript if no colon is used.
+ if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid()))
+ return false;
+
+ assert(OASE && "Expecting array section if not an array subscript.");
+ auto *Length = OASE->getLength();
+
+ // If we don't have a length we have to check if the array has unitary size
+ // for this dimension. Also, we should always expect a length if the base type
+ // is pointer.
+ if (!Length) {
+ if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
+ return ATy->getSize().getSExtValue() != 1;
+ // We cannot assume anything.
+ return false;
+ }
+
+ // Check if the length evaluates to 1.
+ llvm::APSInt ConstLength;
+ if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext()))
+ return false; // Can't get the integer value as a constant.
+
+ return ConstLength.getSExtValue() != 1;
+}
+
// Return the expression of the base of the map clause or null if it cannot
// be determined and do all the necessary checks to see if the expression is
// valid as a standalone map clause expression.
@@ -9132,14 +9220,13 @@ static Expr *CheckMapClauseExpressionBase(Sema &SemaRef, Expr *E) {
Expr *RelevantExpr = nullptr;
- // Flags to help capture some memory
-
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2]
// If a list item is an array section, it must specify contiguous storage.
//
// For this restriction it is sufficient that we make sure only references
// to variables or fields and array expressions, and that no array sections
- // exist except in the rightmost expression. E.g. these would be invalid:
+ // exist except in the rightmost expression (unless they cover the whole
+ // dimension of the array). E.g. these would be invalid:
//
// r.ArrS[3:5].Arr[6:7]
//
@@ -9150,12 +9237,11 @@ static Expr *CheckMapClauseExpressionBase(Sema &SemaRef, Expr *E) {
//
// r.ArrS[3].x
- bool IsRightMostExpression = true;
-
- while (!RelevantExpr) {
- auto AllowArraySection = IsRightMostExpression;
- IsRightMostExpression = false;
+ bool AllowUnitySizeArraySection = true;
+ bool AllowWholeSizeArraySection = true;
+ for (bool IsRightMostExpression = true; !RelevantExpr;
+ IsRightMostExpression = false) {
E = E->IgnoreParenImpCasts();
if (auto *CurE = dyn_cast<DeclRefExpr>(E)) {
@@ -9163,6 +9249,11 @@ static Expr *CheckMapClauseExpressionBase(Sema &SemaRef, Expr *E) {
break;
RelevantExpr = CurE;
+
+ // If we got a reference to a declaration, we should not expect any array
+ // section before that.
+ AllowUnitySizeArraySection = false;
+ AllowWholeSizeArraySection = false;
continue;
}
@@ -9195,9 +9286,7 @@ static Expr *CheckMapClauseExpressionBase(Sema &SemaRef, Expr *E) {
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
// If the type of a list item is a reference to a type T then the type
// will be considered to be T for all purposes of this clause.
- QualType CurType = BaseE->getType();
- if (CurType->isReferenceType())
- CurType = CurType->getPointeeType();
+ QualType CurType = BaseE->getType().getNonReferenceType();
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
// A list item cannot be a variable that is a member of a structure with
@@ -9210,6 +9299,15 @@ static Expr *CheckMapClauseExpressionBase(Sema &SemaRef, Expr *E) {
break;
}
+ // If we got a member expression, we should not expect any array section
+ // before that:
+ //
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
+ // If a list item is an element of a structure, only the rightmost symbol
+ // of the variable reference can be an array section.
+ //
+ AllowUnitySizeArraySection = false;
+ AllowWholeSizeArraySection = false;
continue;
}
@@ -9221,35 +9319,58 @@ static Expr *CheckMapClauseExpressionBase(Sema &SemaRef, Expr *E) {
<< 0 << CurE->getSourceRange();
break;
}
+
+ // If we got an array subscript that express the whole dimension we
+ // can have any array expressions before. If it only expressing part of
+ // the dimension, we can only have unitary-size array expressions.
+ if (CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE,
+ E->getType()))
+ AllowWholeSizeArraySection = false;
continue;
}
if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
- // If a list item is an element of a structure, only the rightmost symbol
- // of the variable reference can be an array section.
- //
- if (!AllowArraySection) {
- SemaRef.Diag(ELoc, diag::err_omp_array_section_in_rightmost_expression)
- << CurE->getSourceRange();
- break;
- }
-
E = CurE->getBase()->IgnoreParenImpCasts();
+ auto CurType =
+ OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
+
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
// If the type of a list item is a reference to a type T then the type
// will be considered to be T for all purposes of this clause.
- QualType CurType = E->getType();
if (CurType->isReferenceType())
CurType = CurType->getPointeeType();
- if (!CurType->isAnyPointerType() && !CurType->isArrayType()) {
+ bool IsPointer = CurType->isAnyPointerType();
+
+ if (!IsPointer && !CurType->isArrayType()) {
SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
<< 0 << CurE->getSourceRange();
break;
}
+ bool NotWhole =
+ CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType);
+ bool NotUnity =
+ CheckArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType);
+
+ if (AllowWholeSizeArraySection && AllowUnitySizeArraySection) {
+ // Any array section is currently allowed.
+ //
+ // If this array section refers to the whole dimension we can still
+ // accept other array sections before this one, except if the base is a
+ // pointer. Otherwise, only unitary sections are accepted.
+ if (NotWhole || IsPointer)
+ AllowWholeSizeArraySection = false;
+ } else if ((AllowUnitySizeArraySection && NotUnity) ||
+ (AllowWholeSizeArraySection && NotWhole)) {
+ // A unity or whole array section is not allowed and that is not
+ // compatible with the properties of the current array section.
+ SemaRef.Diag(
+ ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
+ << CurE->getSourceRange();
+ break;
+ }
continue;
}
OpenPOWER on IntegriCloud