1616#include " clang/Basic/DiagnosticSema.h"
1717#include " clang/Basic/OpenACCKinds.h"
1818#include " clang/Sema/Sema.h"
19+ #include " llvm/ADT/StringExtras.h"
1920#include " llvm/Support/Casting.h"
2021
2122using namespace clang ;
@@ -367,14 +368,26 @@ ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK,
367368 assert (((DK != OpenACCDirectiveKind::Invalid &&
368369 CK == OpenACCClauseKind::Invalid) ||
369370 (DK == OpenACCDirectiveKind::Invalid &&
370- CK != OpenACCClauseKind::Invalid)) &&
371+ CK != OpenACCClauseKind::Invalid) ||
372+ (DK == OpenACCDirectiveKind::Invalid &&
373+ CK == OpenACCClauseKind::Invalid)) &&
371374 " Only one of directive or clause kind should be provided" );
372375
373376 class IntExprConverter : public Sema ::ICEConvertDiagnoser {
374377 OpenACCDirectiveKind DirectiveKind;
375378 OpenACCClauseKind ClauseKind;
376379 Expr *IntExpr;
377380
381+ // gets the index into the diagnostics so we can use this for clauses,
382+ // directives, and sub array.s
383+ unsigned getDiagKind () const {
384+ if (ClauseKind != OpenACCClauseKind::Invalid)
385+ return 0 ;
386+ if (DirectiveKind != OpenACCDirectiveKind::Invalid)
387+ return 1 ;
388+ return 2 ;
389+ }
390+
378391 public:
379392 IntExprConverter (OpenACCDirectiveKind DK, OpenACCClauseKind CK,
380393 Expr *IntExpr)
@@ -390,12 +403,8 @@ ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK,
390403 }
391404 SemaBase::SemaDiagnosticBuilder diagnoseNotInt (Sema &S, SourceLocation Loc,
392405 QualType T) override {
393- if (ClauseKind != OpenACCClauseKind::Invalid)
394- return S.Diag (Loc, diag::err_acc_int_expr_requires_integer) <<
395- /* Clause=*/ 0 << ClauseKind << T;
396-
397- return S.Diag (Loc, diag::err_acc_int_expr_requires_integer) <<
398- /* Directive=*/ 1 << DirectiveKind << T;
406+ return S.Diag (Loc, diag::err_acc_int_expr_requires_integer)
407+ << getDiagKind () << ClauseKind << DirectiveKind << T;
399408 }
400409
401410 SemaBase::SemaDiagnosticBuilder
@@ -503,12 +512,211 @@ ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc,
503512 SourceLocation RBLoc) {
504513 ASTContext &Context = getASTContext ();
505514
506- // TODO OpenACC: We likely have to reproduce a lot of the same logic from the
507- // OMP version of this, but at the moment we don't have a good way to test it,
508- // so for now we'll just create the node.
515+ // Handle placeholders.
516+ if (Base->hasPlaceholderType () &&
517+ !Base->hasPlaceholderType (BuiltinType::ArraySection)) {
518+ ExprResult Result = SemaRef.CheckPlaceholderExpr (Base);
519+ if (Result.isInvalid ())
520+ return ExprError ();
521+ Base = Result.get ();
522+ }
523+ if (LowerBound && LowerBound->getType ()->isNonOverloadPlaceholderType ()) {
524+ ExprResult Result = SemaRef.CheckPlaceholderExpr (LowerBound);
525+ if (Result.isInvalid ())
526+ return ExprError ();
527+ Result = SemaRef.DefaultLvalueConversion (Result.get ());
528+ if (Result.isInvalid ())
529+ return ExprError ();
530+ LowerBound = Result.get ();
531+ }
532+ if (Length && Length->getType ()->isNonOverloadPlaceholderType ()) {
533+ ExprResult Result = SemaRef.CheckPlaceholderExpr (Length);
534+ if (Result.isInvalid ())
535+ return ExprError ();
536+ Result = SemaRef.DefaultLvalueConversion (Result.get ());
537+ if (Result.isInvalid ())
538+ return ExprError ();
539+ Length = Result.get ();
540+ }
541+
542+ // Check the 'base' value, it must be an array or pointer type, and not to/of
543+ // a function type.
544+ QualType OriginalBaseTy = ArraySectionExpr::getBaseOriginalType (Base);
545+ QualType ResultTy;
546+ if (!Base->isTypeDependent ()) {
547+ if (OriginalBaseTy->isAnyPointerType ()) {
548+ ResultTy = OriginalBaseTy->getPointeeType ();
549+ } else if (OriginalBaseTy->isArrayType ()) {
550+ ResultTy = OriginalBaseTy->getAsArrayTypeUnsafe ()->getElementType ();
551+ } else {
552+ return ExprError (
553+ Diag (Base->getExprLoc (), diag::err_acc_typecheck_subarray_value)
554+ << Base->getSourceRange ());
555+ }
556+
557+ if (ResultTy->isFunctionType ()) {
558+ Diag (Base->getExprLoc (), diag::err_acc_subarray_function_type)
559+ << ResultTy << Base->getSourceRange ();
560+ return ExprError ();
561+ }
562+
563+ if (SemaRef.RequireCompleteType (Base->getExprLoc (), ResultTy,
564+ diag::err_acc_subarray_incomplete_type,
565+ Base))
566+ return ExprError ();
567+
568+ if (!Base->hasPlaceholderType (BuiltinType::ArraySection)) {
569+ ExprResult Result = SemaRef.DefaultFunctionArrayLvalueConversion (Base);
570+ if (Result.isInvalid ())
571+ return ExprError ();
572+ Base = Result.get ();
573+ }
574+ }
575+
576+ auto GetRecovery = [&](Expr *E, QualType Ty) {
577+ ExprResult Recovery =
578+ SemaRef.CreateRecoveryExpr (E->getBeginLoc (), E->getEndLoc (), E, Ty);
579+ return Recovery.isUsable () ? Recovery.get () : nullptr ;
580+ };
581+
582+ // Ensure both of the expressions are int-exprs.
583+ if (LowerBound && !LowerBound->isTypeDependent ()) {
584+ ExprResult LBRes =
585+ ActOnIntExpr (OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Invalid,
586+ LowerBound->getExprLoc (), LowerBound);
587+
588+ if (LBRes.isUsable ())
589+ LBRes = SemaRef.DefaultLvalueConversion (LBRes.get ());
590+ LowerBound =
591+ LBRes.isUsable () ? LBRes.get () : GetRecovery (LowerBound, Context.IntTy );
592+ }
593+
594+ if (Length && !Length->isTypeDependent ()) {
595+ ExprResult LenRes =
596+ ActOnIntExpr (OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Invalid,
597+ Length->getExprLoc (), Length);
598+
599+ if (LenRes.isUsable ())
600+ LenRes = SemaRef.DefaultLvalueConversion (LenRes.get ());
601+ Length =
602+ LenRes.isUsable () ? LenRes.get () : GetRecovery (Length, Context.IntTy );
603+ }
604+
605+ // Length is required if the base type is not an array of known bounds.
606+ if (!Length && (OriginalBaseTy.isNull () ||
607+ (!OriginalBaseTy->isDependentType () &&
608+ !OriginalBaseTy->isConstantArrayType () &&
609+ !OriginalBaseTy->isDependentSizedArrayType ()))) {
610+ bool IsArray = !OriginalBaseTy.isNull () && OriginalBaseTy->isArrayType ();
611+ Diag (ColonLoc, diag::err_acc_subarray_no_length) << IsArray;
612+ // Fill in a dummy 'length' so that when we instantiate this we don't
613+ // double-diagnose here.
614+ ExprResult Recovery = SemaRef.CreateRecoveryExpr (
615+ ColonLoc, SourceLocation (), ArrayRef<Expr *>{std::nullopt },
616+ Context.IntTy );
617+ Length = Recovery.isUsable () ? Recovery.get () : nullptr ;
618+ }
619+
620+ // Check the values of each of the arguments, they cannot be negative(we
621+ // assume), and if the array bound is known, must be within range. As we do
622+ // so, do our best to continue with evaluation, we can set the
623+ // value/expression to nullptr/nullopt if they are invalid, and treat them as
624+ // not present for the rest of evaluation.
625+
626+ // We don't have to check for dependence, because the dependent size is
627+ // represented as a different AST node.
628+ std::optional<llvm::APSInt> BaseSize;
629+ if (!OriginalBaseTy.isNull () && OriginalBaseTy->isConstantArrayType ()) {
630+ const auto *ArrayTy = Context.getAsConstantArrayType (OriginalBaseTy);
631+ BaseSize = ArrayTy->getSize ();
632+ }
633+
634+ auto GetBoundValue = [&](Expr *E) -> std::optional<llvm::APSInt> {
635+ if (!E || E->isInstantiationDependent ())
636+ return std::nullopt ;
637+
638+ Expr::EvalResult Res;
639+ if (!E->EvaluateAsInt (Res, Context))
640+ return std::nullopt ;
641+ return Res.Val .getInt ();
642+ };
643+
644+ std::optional<llvm::APSInt> LowerBoundValue = GetBoundValue (LowerBound);
645+ std::optional<llvm::APSInt> LengthValue = GetBoundValue (Length);
646+
647+ // Check lower bound for negative or out of range.
648+ if (LowerBoundValue.has_value ()) {
649+ if (LowerBoundValue->isNegative ()) {
650+ Diag (LowerBound->getExprLoc (), diag::err_acc_subarray_negative)
651+ << /* LowerBound=*/ 0 << toString (*LowerBoundValue, /* Radix=*/ 10 );
652+ LowerBoundValue.reset ();
653+ LowerBound = GetRecovery (LowerBound, LowerBound->getType ());
654+ } else if (BaseSize.has_value () &&
655+ llvm::APSInt::compareValues (*LowerBoundValue, *BaseSize) >= 0 ) {
656+ // Lower bound (start index) must be less than the size of the array.
657+ Diag (LowerBound->getExprLoc (), diag::err_acc_subarray_out_of_range)
658+ << /* LowerBound=*/ 0 << toString (*LowerBoundValue, /* Radix=*/ 10 )
659+ << toString (*BaseSize, /* Radix=*/ 10 );
660+ LowerBoundValue.reset ();
661+ LowerBound = GetRecovery (LowerBound, LowerBound->getType ());
662+ }
663+ }
664+
665+ // Check length for negative or out of range.
666+ if (LengthValue.has_value ()) {
667+ if (LengthValue->isNegative ()) {
668+ Diag (Length->getExprLoc (), diag::err_acc_subarray_negative)
669+ << /* Length=*/ 1 << toString (*LengthValue, /* Radix=*/ 10 );
670+ LengthValue.reset ();
671+ Length = GetRecovery (Length, Length->getType ());
672+ } else if (BaseSize.has_value () &&
673+ llvm::APSInt::compareValues (*LengthValue, *BaseSize) > 0 ) {
674+ // Length must be lessthan or EQUAL to the size of the array.
675+ Diag (Length->getExprLoc (), diag::err_acc_subarray_out_of_range)
676+ << /* Length=*/ 1 << toString (*LengthValue, /* Radix=*/ 10 )
677+ << toString (*BaseSize, /* Radix=*/ 10 );
678+ LengthValue.reset ();
679+ Length = GetRecovery (Length, Length->getType ());
680+ }
681+ }
682+
683+ // Adding two APSInts requires matching sign, so extract that here.
684+ auto AddAPSInt = [](llvm::APSInt LHS, llvm::APSInt RHS) -> llvm::APSInt {
685+ if (LHS.isSigned () == RHS.isSigned ())
686+ return LHS + RHS;
687+
688+ unsigned Width = std::max (LHS.getBitWidth (), RHS.getBitWidth ()) + 1 ;
689+ return llvm::APSInt (LHS.sext (Width) + RHS.sext (Width), /* Signed=*/ true );
690+ };
691+
692+ // If we know all 3 values, we can diagnose that the total value would be out
693+ // of range.
694+ if (BaseSize.has_value () && LowerBoundValue.has_value () &&
695+ LengthValue.has_value () &&
696+ llvm::APSInt::compareValues (AddAPSInt (*LowerBoundValue, *LengthValue),
697+ *BaseSize) > 0 ) {
698+ Diag (Base->getExprLoc (),
699+ diag::err_acc_subarray_base_plus_length_out_of_range)
700+ << toString (*LowerBoundValue, /* Radix=*/ 10 )
701+ << toString (*LengthValue, /* Radix=*/ 10 )
702+ << toString (*BaseSize, /* Radix=*/ 10 );
703+
704+ LowerBoundValue.reset ();
705+ LowerBound = GetRecovery (LowerBound, LowerBound->getType ());
706+ LengthValue.reset ();
707+ Length = GetRecovery (Length, Length->getType ());
708+ }
709+
710+ // If any part of the expression is dependent, return a dependent sub-array.
711+ QualType ArrayExprTy = Context.ArraySectionTy ;
712+ if (Base->isTypeDependent () ||
713+ (LowerBound && LowerBound->isInstantiationDependent ()) ||
714+ (Length && Length->isInstantiationDependent ()))
715+ ArrayExprTy = Context.DependentTy ;
716+
509717 return new (Context)
510- ArraySectionExpr (Base, LowerBound, Length, Context. ArraySectionTy ,
511- VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
718+ ArraySectionExpr (Base, LowerBound, Length, ArrayExprTy, VK_LValue ,
719+ OK_Ordinary, ColonLoc, RBLoc);
512720}
513721
514722bool SemaOpenACC::ActOnStartStmtDirective (OpenACCDirectiveKind K,
0 commit comments