Added tests for array sections serialization/deserialization/AST printing.

http://reviews.llvm.org/D10732

Files:
  include/clang-c/Index.h
  include/clang/AST/DataRecursiveASTVisitor.h
  include/clang/AST/Expr.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/StmtNodes.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/Parse/ParseExpr.cpp
  lib/Parse/ParseOpenMP.cpp
  lib/Parse/Parser.cpp
  lib/Parse/RAIIObjectsForParser.h
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOpenMP.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
  lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/OpenMP/task_ast_print.cpp
  test/OpenMP/task_depend_messages.cpp
  tools/libclang/CIndex.cpp
  tools/libclang/CXCursor.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/OpenMP/task_depend_messages.cpp
===================================================================
--- test/OpenMP/task_depend_messages.cpp
+++ test/OpenMP/task_depend_messages.cpp
@@ -33,6 +33,20 @@
   #pragma omp task depend (in : ) // expected-error {{expected expression}}
   #pragma omp task depend (in : main) // expected-error {{expected variable name, array element or array section}}
   #pragma omp task depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+  #pragma omp task depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
+  #pragma omp task depend (in : argv[ // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
+  #pragma omp task depend (in : argv[: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
+  #pragma omp task depend (in : argv[:] // expected-error {{section length is undefined, but subscripted value is not a sized array}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task depend (in : argv[argc: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
+  #pragma omp task depend (in : argv[argc:argc] // expected-error {{expected ')'}} expected-note {{to match this '('}}
+  #pragma omp task depend (in : argv[0:-1]) // expected-error {{section length is evaluated to a negative value}}
+  #pragma omp task depend (in : argv[-1:0]) // expected-error {{section lower bound is evaluated to a negative value}}
+  #pragma omp task depend (in : argv[:]) // expected-error {{section length is undefined, but subscripted value is not a sized array}}
+  #pragma omp task depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}}
+  #pragma omp task depend(in:a[0:1]) // expected-error {{subscripted value is not an array or pointer}}
+  #pragma omp task depend(in:argv[argv[:]:1]) // expected-error {{expected expression}} expected-error {{expected ']'}} expected-note {{to match this '['}}
+  #pragma omp task depend(in:argv[0:][:]) // expected-error {{section length is undefined, but subscripted value is not a sized array}}
+  #pragma omp task depend(in : argv[ : argc][1 : argc - 1])
   foo();
 
   return 0;
Index: test/OpenMP/task_ast_print.cpp
===================================================================
--- test/OpenMP/task_ast_print.cpp
+++ test/OpenMP/task_ast_print.cpp
@@ -33,7 +33,7 @@
   T b = argc, c, d, e, f, g;
   static T a;
   S<T> s;
-#pragma omp task untied depend(in : argc)
+#pragma omp task untied depend(in : argc, argv[b:argc])
   a = 2;
 #pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0)
   foo();
@@ -46,7 +46,7 @@
 // CHECK-NEXT: int b = argc, c, d, e, f, g;
 // CHECK-NEXT: static int a;
 // CHECK-NEXT: S<int> s;
-// CHECK-NEXT: #pragma omp task untied depend(in : argc)
+// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc])
 // CHECK-NEXT: a = 2;
 // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0)
 // CHECK-NEXT: foo()
@@ -56,7 +56,7 @@
 // CHECK-NEXT: long b = argc, c, d, e, f, g;
 // CHECK-NEXT: static long a;
 // CHECK-NEXT: S<long> s;
-// CHECK-NEXT: #pragma omp task untied depend(in : argc)
+// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc])
 // CHECK-NEXT: a = 2;
 // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0)
 // CHECK-NEXT: foo()
@@ -66,7 +66,7 @@
 // CHECK-NEXT: T b = argc, c, d, e, f, g;
 // CHECK-NEXT: static T a;
 // CHECK-NEXT: S<T> s;
-// CHECK-NEXT: #pragma omp task untied depend(in : argc)
+// CHECK-NEXT: #pragma omp task untied depend(in : argc,argv[b:argc])
 // CHECK-NEXT: a = 2;
 // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0)
 // CHECK-NEXT: foo()
@@ -86,8 +86,8 @@
   // CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[1])
   a = 2;
 // CHECK-NEXT: a = 2;
-#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a)
-  // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a)
+#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc])
+  // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc])
   foo();
   // CHECK-NEXT: foo();
   return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -62,6 +62,7 @@
 def OffsetOfExpr : DStmt<Expr>;
 def UnaryExprOrTypeTraitExpr : DStmt<Expr>;
 def ArraySubscriptExpr : DStmt<Expr>;
+def ArraySectionExpr : DStmt<Expr>;
 def CallExpr : DStmt<Expr>;
 def MemberExpr : DStmt<Expr>;
 def CastExpr : DStmt<Expr, 1>;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4869,6 +4869,21 @@
 def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
   InGroup<CharSubscript>, DefaultIgnore;
 
+def err_typecheck_section_value : Error<
+  "subscripted value is not an array or pointer">;
+def err_typecheck_section_not_integer : Error<
+  "array section %select{lower bound|length}0 is not an integer">;
+def err_section_function_type : Error<
+  "section of pointer to function type %0">;
+def warn_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">,
+  InGroup<CharSubscript>, DefaultIgnore;
+def err_section_incomplete_type : Error<
+  "section of pointer to incomplete type %0">;
+def err_section_negative : Error<
+  "section %select{lower bound|length}0 is evaluated to a negative value">;
+def err_section_length_undefined : Error<
+  "section length is undefined, but subscripted value is not a sized array">;
+
 def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
 def err_no_member : Error<"no member named %0 in %1">;
 def err_no_member_overloaded_arrow : Error<
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3776,6 +3776,9 @@
                                      Expr *Idx, SourceLocation RLoc);
   ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
                                              Expr *Idx, SourceLocation RLoc);
+  ExprResult ActOnArraySectionExpr(Scope *S, Expr *Base, SourceLocation LBLoc,
+                                   Expr *LowerBound, SourceLocation ColonLoc,
+                                   Expr *Length, SourceLocation RBLoc);
 
   // This struct is for use by ActOnMemberAccess to allow
   // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -2142,6 +2142,110 @@
   }
 };
 
+/// \brief OpenMP 4.0 [2.4, Array Sections].
+/// To specify an array section in an OpenMP construct, array subscript
+/// expressions are extended with the following syntax:
+/// \code
+/// [ lower-bound : length ]
+/// [ lower-bound : ]
+/// [ : length ]
+/// [ : ]
+/// \endcode
+/// The array section must be a subset of the original array.
+/// Array sections are allowed on multidimensional arrays. Base language array
+/// subscript expressions can be used to specify length-one dimensions of
+/// multidimensional array sections.
+/// The lower-bound and length are integral type expressions. When evaluated
+/// they represent a set of integer values as follows:
+/// \code
+/// { lower-bound, lower-bound + 1, lower-bound + 2,... , lower-bound + length -
+/// 1 }
+/// \endcode
+/// The lower-bound and length must evaluate to non-negative integers.
+/// When the size of the array dimension is not known, the length must be
+/// specified explicitly.
+/// When the length is absent, it defaults to the size of the array dimension
+/// minus the lower-bound.
+/// When the lower-bound is absent it defaults to 0.
+class ArraySectionExpr : public Expr {
+  enum { BASE, LOWER_BOUND, LENGTH, END_EXPR };
+  Stmt *SubExprs[END_EXPR];
+  SourceLocation ColonLoc;
+  SourceLocation RBracketLoc;
+
+public:
+  ArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type,
+                   ExprValueKind VK, ExprObjectKind OK, SourceLocation ColonLoc,
+                   SourceLocation RBracketLoc)
+      : Expr(
+            ArraySectionExprClass, Type, VK, OK,
+            Base->isTypeDependent() ||
+                (LowerBound && LowerBound->isTypeDependent()) ||
+                (Length && Length->isTypeDependent()),
+            Base->isValueDependent() ||
+                (LowerBound && LowerBound->isValueDependent()) ||
+                (Length && Length->isValueDependent()),
+            Base->isInstantiationDependent() ||
+                (LowerBound && LowerBound->isInstantiationDependent()) ||
+                (Length && Length->isInstantiationDependent()),
+            Base->containsUnexpandedParameterPack() ||
+                (LowerBound && LowerBound->containsUnexpandedParameterPack()) ||
+                (Length && Length->containsUnexpandedParameterPack())),
+        ColonLoc(ColonLoc), RBracketLoc(RBracketLoc) {
+    SubExprs[BASE] = Base;
+    SubExprs[LOWER_BOUND] = LowerBound;
+    SubExprs[LENGTH] = Length;
+  }
+
+  /// \brief Create an empty array section expression.
+  explicit ArraySectionExpr(EmptyShell Shell)
+      : Expr(ArraySectionExprClass, Shell) {}
+
+  /// An array section can be written only as Base[LowerBound:Length].
+
+  /// \brief Get base of the array section.
+  Expr *getBase() { return cast<Expr>(SubExprs[BASE]); }
+  const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
+  /// \brief Set base of the array section.
+  void setBase(Expr *E) { SubExprs[BASE] = E; }
+
+  /// \brief Get lower bound of array section.
+  Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); }
+  const Expr *getLowerBound() const {
+    return cast_or_null<Expr>(SubExprs[LOWER_BOUND]);
+  }
+  /// \brief Set lower bound of the array section.
+  void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; }
+
+  /// \brief Get length of array section.
+  Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); }
+  const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); }
+  /// \brief Set length of the array section.
+  void setLength(Expr *E) { SubExprs[LENGTH] = E; }
+
+  SourceLocation getLocStart() const LLVM_READONLY {
+    return getBase()->getLocStart();
+  }
+  SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; }
+
+  SourceLocation getColonLoc() const { return ColonLoc; }
+  void setColonLoc(SourceLocation L) { ColonLoc = L; }
+
+  SourceLocation getRBracketLoc() const { return RBracketLoc; }
+  void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
+
+  SourceLocation getExprLoc() const LLVM_READONLY {
+    return getBase()->getExprLoc();
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ArraySectionExprClass;
+  }
+
+  child_range children() {
+    return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
+  }
+};
 
 /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
 /// CallExpr itself represents a normal function call, e.g., "f(x, 2)",
Index: include/clang/AST/DataRecursiveASTVisitor.h
===================================================================
--- include/clang/AST/DataRecursiveASTVisitor.h
+++ include/clang/AST/DataRecursiveASTVisitor.h
@@ -2174,6 +2174,7 @@
 // over the children.
 DEF_TRAVERSE_STMT(AddrLabelExpr, {})
 DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
+DEF_TRAVERSE_STMT(ArraySectionExpr, {})
 DEF_TRAVERSE_STMT(BlockExpr, {
   TRY_TO(TraverseDecl(S->getBlockDecl()));
   return true; // no child statements to loop through.
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2207,6 +2207,7 @@
 // over the children.
 DEF_TRAVERSE_STMT(AddrLabelExpr, {})
 DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
+DEF_TRAVERSE_STMT(ArraySectionExpr, {})
 DEF_TRAVERSE_STMT(BlockExpr, {
   TRY_TO(TraverseDecl(S->getBlockDecl()));
   return true; // no child statements to loop through.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -55,6 +55,7 @@
   friend class ColonProtectionRAIIObject;
   friend class InMessageExpressionRAIIObject;
   friend class PoisonSEHIdentifiersRAIIObject;
+  friend class ArraySectionExpressionRAIIObject;
   friend class ObjCDeclContextSwitch;
   friend class ParenBraceBracketBalancer;
   friend class BalancedDelimiterTracker;
@@ -179,6 +180,11 @@
   /// ColonProtectionRAIIObject RAII object.
   bool ColonIsSacred;
 
+  /// \brief If true, parsing of array sections is supported. Otherwise, only
+  /// array subscripts are allowed.  This is managed by the
+  /// ArraySectionExpressionRAIIObject RAII object.
+  bool ArraySectionAllowed;
+
   /// \brief When true, we are directly inside an Objective-C message
   /// send expression.
   ///
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1397,6 +1397,7 @@
       STMT_OMP_TARGET_DIRECTIVE,
       STMT_OMP_TEAMS_DIRECTIVE,
       STMT_OMP_TASKGROUP_DIRECTIVE,
+      EXPR_ARRAY_SECTION,
 
       // ARC
       EXPR_OBJC_BRIDGED_CAST,     // ObjCBridgedCastExpr
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -1982,7 +1982,11 @@
    */
   CXCursor_ObjCSelfExpr                  = 146,
 
-  CXCursor_LastExpr                      = CXCursor_ObjCSelfExpr,
+  /** \brief OpenMP 4.0 [2.4, Array Section].
+   */
+  CXCursor_ArraySectionExpr              = 147,
+
+  CXCursor_LastExpr                      = CXCursor_ArraySectionExpr,
 
   /* Statements */
   CXCursor_FirstStmt                     = 200,
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -328,6 +328,10 @@
     K = CXCursor_ArraySubscriptExpr;
     break;
 
+  case Stmt::ArraySectionExprClass:
+    K = CXCursor_ArraySectionExpr;
+    break;
+
   case Stmt::BinaryOperatorClass:
     K = CXCursor_BinaryOperator;
     break;
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -4003,6 +4003,8 @@
       return cxstring::createRef("UnaryOperator");
   case CXCursor_ArraySubscriptExpr:
       return cxstring::createRef("ArraySubscriptExpr");
+  case CXCursor_ArraySectionExpr:
+      return cxstring::createRef("ArraySectionExpr");
   case CXCursor_BinaryOperator:
       return cxstring::createRef("BinaryOperator");
   case CXCursor_CompoundAssignOperator:
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1835,6 +1835,18 @@
                                              RBracketLoc);
   }
 
+  /// \brief Build a new array section expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildArraySectionExpr(Expr *Base, SourceLocation LBracketLoc,
+                                     Expr *LowerBound, SourceLocation ColonLoc,
+                                     Expr *Length, SourceLocation RBracketLoc) {
+    return getSema().ActOnArraySectionExpr(/*Scope=*/nullptr, Base, LBracketLoc,
+                                           LowerBound, ColonLoc, Length,
+                                           RBracketLoc);
+  }
+
   /// \brief Build a new call expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -7644,6 +7656,36 @@
                                                 E->getRBracketLoc());
 }
 
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformArraySectionExpr(ArraySectionExpr *E) {
+  ExprResult Base = getDerived().TransformExpr(E->getBase());
+  if (Base.isInvalid())
+    return ExprError();
+
+  ExprResult LowerBound;
+  if (E->getLowerBound()) {
+    LowerBound = getDerived().TransformExpr(E->getLowerBound());
+    if (LowerBound.isInvalid())
+      return ExprError();
+  }
+
+  ExprResult Length;
+  if (E->getLength()) {
+    Length = getDerived().TransformExpr(E->getLength());
+    if (Length.isInvalid())
+      return ExprError();
+  }
+
+  if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() &&
+      LowerBound.get() == E->getLowerBound() && Length.get() == E->getLength())
+    return E;
+
+  return getDerived().RebuildArraySectionExpr(
+      Base.get(), E->getBase()->getLocEnd(), LowerBound.get(), E->getColonLoc(),
+      Length.get(), E->getRBracketLoc());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -6397,10 +6397,11 @@
     //  structure) but is not an array element or an array section cannot appear
     //  in a depend clause.
     auto *SimpleExpr = RefExpr->IgnoreParenCasts();
-    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
-    ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
-    if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE) ||
-        (DE && !isa<VarDecl>(DE->getDecl())) ||
+    auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
+    auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
+    auto *ASecE = dyn_cast<ArraySectionExpr>(SimpleExpr);
+    if ((!RefExpr->IgnoreParenImpCasts()->isLValue() && !ASecE) ||
+        (!ASE && !DE && !ASecE) || (DE && !isa<VarDecl>(DE->getDecl())) ||
         (ASE && !ASE->getBase()->getType()->isAnyPointerType() &&
          !ASE->getBase()->getType()->isArrayType())) {
       Diag(ELoc, diag::err_omp_expected_var_name_or_array_item)
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1057,6 +1057,7 @@
 
     // Some might be dependent for other reasons.
   case Expr::ArraySubscriptExprClass:
+  case Expr::ArraySectionExprClass:
   case Expr::BinaryOperatorClass:
   case Expr::CompoundAssignOperatorClass:
   case Expr::CStyleCastExprClass:
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5683,6 +5683,10 @@
     return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl);
   }
 
+  case Stmt::ArraySectionExprClass: {
+    return EvalAddr(cast<ArraySectionExpr>(E)->getBase(), refVars,ParentDecl);
+  }
+
   case Stmt::ConditionalOperatorClass: {
     // For conditional operators we need to see if either the LHS or RHS are
     // non-NULL Expr's.  If one is non-NULL, we return it.
@@ -8293,6 +8297,13 @@
                          AllowOnePastEnd > 0);
         return;
       }
+      case Stmt::ArraySectionExprClass: {
+        const ArraySectionExpr *ASE = cast<ArraySectionExpr>(expr);
+        if (ASE->getLowerBound())
+          CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(),
+                           /**ASE=*/nullptr, AllowOnePastEnd > 0);
+        return;
+      }
       case Stmt::UnaryOperatorClass: {
         // Only unwrap the * and & unary operators
         const UnaryOperator *UO = cast<UnaryOperator>(expr);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3988,6 +3988,155 @@
   return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
 }
 
+ExprResult Sema::ActOnArraySectionExpr(Scope *S, Expr *Base,
+                                       SourceLocation LBLoc, Expr *LowerBound,
+                                       SourceLocation ColonLoc, Expr *Length,
+                                       SourceLocation RBLoc) {
+  // Since this might be a postfix expression, get rid of ParenListExprs.
+  if (isa<ParenListExpr>(Base)) {
+    ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
+    if (Result.isInvalid())
+      return ExprError();
+    Base = Result.get();
+  }
+
+  // Handle any non-overload placeholder types in the base and index
+  // expressions.  We can't handle overloads here because the other
+  // operand might be an overloadable type, in which case the overload
+  // resolution for the operator overload should get the first crack
+  // at the overload.
+  if (Base->getType()->isNonOverloadPlaceholderType()) {
+    ExprResult Result = CheckPlaceholderExpr(Base);
+    if (Result.isInvalid())
+      return ExprError();
+    Base = Result.get();
+  }
+  if (LowerBound && LowerBound->getType()->isNonOverloadPlaceholderType()) {
+    ExprResult Result = CheckPlaceholderExpr(LowerBound);
+    if (Result.isInvalid())
+      return ExprError();
+    LowerBound = Result.get();
+  }
+  if (Length && Length->getType()->isNonOverloadPlaceholderType()) {
+    ExprResult Result = CheckPlaceholderExpr(Length);
+    if (Result.isInvalid())
+      return ExprError();
+    Length = Result.get();
+  }
+
+  // Build an unanalyzed expression if either operand is type-dependent.
+  if (Base->isTypeDependent() ||
+      (LowerBound && LowerBound->isTypeDependent()) ||
+      (Length && Length->isTypeDependent())) {
+    return new (Context)
+        ArraySectionExpr(Base, LowerBound, Length, Context.DependentTy,
+                         VK_RValue, OK_Ordinary, ColonLoc, RBLoc);
+  }
+
+  // Perform default conversions.
+  auto *BaseArrayTy = Base->getType()->getAsArrayTypeUnsafe();
+  ExprResult Result = DefaultFunctionArrayLvalueConversion(Base);
+  if (Result.isInvalid())
+    return ExprError();
+  Base = Result.get();
+
+  QualType ResultType;
+  if (const PointerType *PTy = Base->getType()->getAs<PointerType>()) {
+    ResultType = PTy->getPointeeType();
+  } else if (Base->getType()->isArrayType()) {
+    // If we see an array that wasn't promoted by
+    // DefaultFunctionArrayLvalueConversion, it must be an array that wasn't
+    // promoted because of the C90 rule that doesn't allow promoting non-lvalue
+    // arrays.  Warn, then force the promotion here.
+    Diag(Base->getLocStart(), diag::ext_subscript_non_lvalue)
+        << Base->getSourceRange();
+    Base = ImpCastExprToType(Base, Context.getArrayDecayedType(Base->getType()),
+                             CK_ArrayToPointerDecay)
+               .get();
+    ResultType = Base->getType()->getAs<PointerType>()->getPointeeType();
+  } else {
+    return ExprError(Diag(Base->getExprLoc(), diag::err_typecheck_section_value)
+                     << Base->getSourceRange());
+  }
+  // C99 6.5.2.1p1
+  if (LowerBound) {
+    if (!LowerBound->getType()->isIntegerType())
+      return ExprError(Diag(LowerBound->getExprLoc(),
+                            diag::err_typecheck_section_not_integer)
+                       << 0 << LowerBound->getSourceRange());
+
+    if (LowerBound->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
+        LowerBound->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
+      Diag(LowerBound->getExprLoc(), diag::warn_section_is_char)
+          << 0 << LowerBound->getSourceRange();
+  }
+  if (Length) {
+    if (!Length->getType()->isIntegerType())
+      return ExprError(
+          Diag(Length->getExprLoc(), diag::err_typecheck_section_not_integer)
+          << 1 << Length->getSourceRange());
+
+    if (Length->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
+        Length->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
+      Diag(Length->getExprLoc(), diag::warn_section_is_char)
+          << 1 << Length->getSourceRange();
+  }
+
+  // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
+  // C++ [expr.sub]p1: The type "T" shall be a completely-defined object
+  // type. Note that Functions are not objects, and that (in C99 parlance)
+  // incomplete types are not object types.
+  if (ResultType->isFunctionType()) {
+    Diag(Base->getExprLoc(), diag::err_section_function_type)
+        << ResultType << Base->getSourceRange();
+    return ExprError();
+  }
+
+  if (RequireCompleteType(Base->getExprLoc(), ResultType,
+                          diag::err_section_incomplete_type, Base))
+    return ExprError();
+
+  if (LowerBound) {
+    llvm::APSInt LowerBoundValue;
+    if (LowerBound->EvaluateAsInt(LowerBoundValue, Context,
+                                  Expr::SE_AllowSideEffects)) {
+      // OpenMP 4.0, [2.4 Array Sections]
+      // The lower-bound and length must evaluate to non-negative integers.
+      if (LowerBoundValue.isNegative()) {
+        Diag(LowerBound->getExprLoc(), diag::err_section_negative)
+            << 0 << LowerBound->getSourceRange();
+        return ExprError();
+      }
+    }
+  }
+
+  if (Length) {
+    llvm::APSInt LengthValue;
+    if (Length->EvaluateAsInt(LengthValue, Context,
+                              Expr::SE_AllowSideEffects)) {
+      // OpenMP 4.0, [2.4 Array Sections]
+      // The lower-bound and length must evaluate to non-negative integers.
+      if (LengthValue.isNegative()) {
+        Diag(Length->getExprLoc(), diag::err_section_negative)
+            << 1 << Length->getSourceRange();
+        return ExprError();
+      }
+    }
+  } else {
+    // OpenMP 4.0, [2.4 Array Sections]
+    // When the size of the array dimension is not known, the length must be
+    // specified explicitly.
+    if (!BaseArrayTy) {
+      Diag(ColonLoc, diag::err_section_length_undefined);
+      return ExprError();
+    }
+  }
+
+  return new (Context)
+      ArraySectionExpr(Base, LowerBound, Length, ResultType, VK_RValue,
+                       OK_Ordinary, ColonLoc, RBLoc);
+}
+
 ExprResult
 Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
                                       Expr *Idx, SourceLocation RLoc) {
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -8670,6 +8670,7 @@
   case Expr::ImaginaryLiteralClass:
   case Expr::StringLiteralClass:
   case Expr::ArraySubscriptExprClass:
+  case Expr::ArraySectionExprClass:
   case Expr::MemberExprClass:
   case Expr::CompoundAssignOperatorClass:
   case Expr::CompoundLiteralExprClass:
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2687,6 +2687,7 @@
   case Expr::LambdaExprClass:
   case Expr::MSPropertyRefExprClass:
   case Expr::TypoExprClass:  // This should no longer exist in the AST by now.
+  case Expr::ArraySectionExprClass:
     llvm_unreachable("unexpected statement kind");
 
   // FIXME: invent manglings for all these.
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1251,6 +1251,17 @@
   OS << "]";
 }
 
+void StmtPrinter::VisitArraySectionExpr(ArraySectionExpr *Node) {
+  PrintExpr(Node->getBase());
+  OS << "[";
+  if (Node->getLowerBound())
+    PrintExpr(Node->getLowerBound());
+  OS << ":";
+  if (Node->getLength())
+    PrintExpr(Node->getLength());
+  OS << "]";
+}
+
 void StmtPrinter::PrintCallArgs(CallExpr *Call) {
   for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
     if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -637,6 +637,10 @@
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitArraySectionExpr(const ArraySectionExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitCallExpr(const CallExpr *S) {
   VisitExpr(S);
 }
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -3012,6 +3012,7 @@
 
   case ParenExprClass:
   case ArraySubscriptExprClass:
+  case ArraySectionExprClass:
   case MemberExprClass:
   case ConditionalOperatorClass:
   case BinaryConditionalOperatorClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -185,6 +185,7 @@
   case Expr::CXXFoldExprClass:
   case Expr::NoInitExprClass:
   case Expr::DesignatedInitUpdateExprClass:
+  case Expr::ArraySectionExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.
Index: lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -130,6 +130,14 @@
     os << " results in a null pointer dereference";
     break;
   }
+  case Stmt::ArraySectionExprClass: {
+    os << "Array access";
+    const ArraySectionExpr *AE = cast<ArraySectionExpr>(S);
+    AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
+                   State.get(), N->getLocationContext());
+    os << " results in a null pointer dereference";
+    break;
+  }
   case Stmt::UnaryOperatorClass: {
     os << "Dereference of null pointer";
     const UnaryOperator *U = cast<UnaryOperator>(S);
Index: lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -332,6 +332,7 @@
     return false;
   case Stmt::CallExprClass:
   case Stmt::ArraySubscriptExprClass:
+  case Stmt::ArraySectionExprClass:
   case Stmt::ImplicitCastExprClass:
   case Stmt::ParenExprClass:
   case Stmt::BreakStmtClass:
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -899,7 +899,8 @@
     case Stmt::ObjCStringLiteralClass:
     case Stmt::CXXPseudoDestructorExprClass:
     case Stmt::SubstNonTypeTemplateParmExprClass:
-    case Stmt::CXXNullPtrLiteralExprClass: {
+    case Stmt::CXXNullPtrLiteralExprClass:
+    case Stmt::ArraySectionExprClass: {
       Bldr.takeNodes(Pred);
       ExplodedNodeSet preVisit;
       getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -1394,21 +1394,46 @@
       BalancedDelimiterTracker T(*this, tok::l_square);
       T.consumeOpen();
       Loc = T.getOpenLocation();
-      ExprResult Idx;
+      ExprResult Idx, Length;
+      bool ArraySectionIsFound = false;
+      SourceLocation ColonLoc;
       if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
         Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
         Idx = ParseBraceInitializer();
-      } else
-        Idx = ParseExpression();
+      } else {
+        bool MayArraySection = ArraySectionAllowed;
+        ArraySectionExpressionRAIIObject RAII(*this, /*Value=*/false);
+        // Parse [: or [ expr or [ expr :
+        if (!MayArraySection || !Tok.is(tok::colon)) {
+          // [ expr
+          Idx = ParseExpression();
+        }
+        if (MayArraySection && Tok.is(tok::colon)) {
+          // Consume ':'
+          ArraySectionIsFound = true;
+          ColonLoc = ConsumeToken();
+          if (Tok.isNot(tok::r_square)) {
+            Length = ParseExpression();
+          }
+        }
+      }
 
       SourceLocation RLoc = Tok.getLocation();
 
-      if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) {
-        LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
-                                              Idx.get(), RLoc);
+      if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() &&
+          Tok.is(tok::r_square)) {
+        if (ArraySectionIsFound) {
+          LHS = Actions.ActOnArraySectionExpr(getCurScope(), LHS.get(), Loc,
+                                              Idx.get(), ColonLoc, Length.get(),
+                                              RLoc);
+        } else {
+          LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
+                                                Idx.get(), RLoc);
+        }
       } else {
         (void)Actions.CorrectDelayedTyposInExpr(LHS);
         (void)Actions.CorrectDelayedTyposInExpr(Idx);
+        (void)Actions.CorrectDelayedTyposInExpr(Length);
         LHS = ExprError();
         Idx = ExprError();
       }
Index: lib/Parse/RAIIObjectsForParser.h
===================================================================
--- lib/Parse/RAIIObjectsForParser.h
+++ lib/Parse/RAIIObjectsForParser.h
@@ -286,7 +286,27 @@
       restore();
     }
   };
-  
+
+  /// \brief This sets the Parser::ArraySectionAllowed bool and
+  /// restores it when destroyed. It it also manages Parser::ColonIsSacred for
+  /// correct parsing of array sections.
+  class ArraySectionExpressionRAIIObject {
+    Parser &P;
+    bool OldVal;
+
+  public:
+    ArraySectionExpressionRAIIObject(Parser &p, bool Value = true)
+        : P(p), OldVal(P.ArraySectionAllowed) {
+      P.ArraySectionAllowed = Value;
+    }
+
+    /// restore - This can be used to restore the state early, before the dtor
+    /// is run.
+    void restore() { P.ArraySectionAllowed = OldVal; }
+
+    ~ArraySectionExpressionRAIIObject() { restore(); }
+  };
+
   /// \brief RAII object that makes '>' behave either as an operator
   /// or as the closing angle bracket for a template argument list.
   class GreaterThanIsOperatorScope {
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -739,7 +739,9 @@
   const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
   while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
                      Tok.isNot(tok::annot_pragma_openmp_end))) {
-    ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
+    ArraySectionExpressionRAIIObject RAII(*this, Kind == OMPC_depend);
+    ColonProtectionRAIIObject ColonRAII(*this,
+                                        Kind == OMPC_depend || MayHaveTail);
     // Parse variable
     ExprResult VarExpr =
         Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -69,10 +69,10 @@
 }
 
 Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
-  : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
-    GreaterThanIsOperator(true), ColonIsSacred(false), 
-    InMessageExpression(false), TemplateParameterDepth(0),
-    ParsingInObjCContainer(false) {
+    : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+      GreaterThanIsOperator(true), ColonIsSacred(false),
+      ArraySectionAllowed(false), InMessageExpression(false),
+      TemplateParameterDepth(0), ParsingInObjCContainer(false) {
   SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
   Tok.startToken();
   Tok.setKind(tok::eof);
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -589,6 +589,15 @@
   E->setRBracketLoc(ReadSourceLocation(Record, Idx));
 }
 
+void ASTStmtReader::VisitArraySectionExpr(ArraySectionExpr *E) {
+  VisitExpr(E);
+  E->setBase(Reader.ReadSubExpr());
+  E->setLowerBound(Reader.ReadSubExpr());
+  E->setLength(Reader.ReadSubExpr());
+  E->setColonLoc(ReadSourceLocation(Record, Idx));
+  E->setRBracketLoc(ReadSourceLocation(Record, Idx));
+}
+
 void ASTStmtReader::VisitCallExpr(CallExpr *E) {
   VisitExpr(E);
   E->setNumArgs(Reader.getContext(), Record[Idx++]);
@@ -2480,6 +2489,10 @@
       S = new (Context) ArraySubscriptExpr(Empty);
       break;
 
+    case EXPR_ARRAY_SECTION:
+      S = new (Context) ArraySectionExpr(Empty);
+      break;
+
     case EXPR_CALL:
       S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty);
       break;
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -511,6 +511,16 @@
   Code = serialization::EXPR_ARRAY_SUBSCRIPT;
 }
 
+void ASTStmtWriter::VisitArraySectionExpr(ArraySectionExpr *E) {
+  VisitExpr(E);
+  Writer.AddStmt(E->getBase());
+  Writer.AddStmt(E->getLowerBound());
+  Writer.AddStmt(E->getLength());
+  Writer.AddSourceLocation(E->getColonLoc(), Record);
+  Writer.AddSourceLocation(E->getRBracketLoc(), Record);
+  Code = serialization::EXPR_ARRAY_SECTION;
+}
+
 void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
   VisitExpr(E);
   Record.push_back(E->getNumArgs());
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to