[clang-tools-extra] c151225 - [C++2b] Implement multidimentional subscript operator
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 8 09:10:59 PST 2022
Author: Corentin Jabot
Date: 2022-02-08T12:10:47-05:00
New Revision: c1512250960bd247519a9f959ad4af202402dcc4
URL: https://github.com/llvm/llvm-project/commit/c1512250960bd247519a9f959ad4af202402dcc4
DIFF: https://github.com/llvm/llvm-project/commit/c1512250960bd247519a9f959ad4af202402dcc4.diff
LOG: [C++2b] Implement multidimentional subscript operator
Implement P2128R6 in C++23 mode.
Unlike GCC's implementation, this doesn't try to recover when a user
meant to use a comma expression.
Because the syntax changes meaning in C++23, the patch is *NOT*
implemented as an extension. Instead, declaring an array with not
exactly 1 parameter is an error in older languages modes. There is an
off-by-default extension warning in C++23 mode.
Unlike the standard, we supports default arguments;
Ie, we assume, based on conversations in WG21, that the proposed
resolution to CWG2507 will be accepted.
We allow arrays OpenMP sections and C++23 multidimensional array to
coexist:
[a , b] multi dimensional array
[a : b] open mp section
[a, b: c] // error
The rest of the patch is relatively straight forward: we take care to
support an arbitrary number of arguments everywhere.
Added:
clang/test/Parser/cxx2b-subscript.cpp
clang/test/SemaCXX/cxx2b-overloaded-operator.cpp
Modified:
clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/StmtPrinter.cpp
clang/lib/Frontend/InitPreprocessor.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Sema/SemaAccess.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/TreeTransform.h
clang/test/OpenMP/target_update_messages.cpp
clang/test/SemaTemplate/instantiate-subscript.cpp
clang/www/cxx_status.html
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
index d29e631641dcb..5d4f3b8249249 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -398,8 +398,8 @@ static bool isAliasDecl(ASTContext *Context, const Decl *TheDecl,
if (OpCall->getOperator() == OO_Star)
return isDereferenceOfOpCall(OpCall, IndexVar);
if (OpCall->getOperator() == OO_Subscript) {
- assert(OpCall->getNumArgs() == 2);
- return isIndexInSubscriptExpr(OpCall->getArg(1), IndexVar);
+ return OpCall->getNumArgs() == 2 &&
+ isIndexInSubscriptExpr(OpCall->getArg(1), IndexVar);
}
break;
}
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8704b4f79cd88..7f568dcb591ec 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -92,6 +92,8 @@ C++20 Feature Support
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
+- Implemented `P2128R6: Multidimensional subscript operator <https://wg21.link/P2128R6>`_.
+
CUDA Language Changes in Clang
------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 08cd8c8991ff9..1ea74e5e97f64 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4666,6 +4666,8 @@ def err_ovl_no_viable_object_call : Error<
"no matching function for call to object of type %0">;
def err_ovl_ambiguous_object_call : Error<
"call to object of type %0 is ambiguous">;
+def err_ovl_ambiguous_subscript_call : Error<
+ "call to subscript operator of type %0 is ambiguous">;
def err_ovl_deleted_object_call : Error<
"call to deleted function call operator in type %0">;
def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
@@ -6571,7 +6573,8 @@ def err_arithmetic_nonfragile_interface : Error<
"this architecture and platform">;
def warn_deprecated_comma_subscript : Warning<
- "top-level comma expression in array subscript is deprecated">,
+ "top-level comma expression in array subscript is deprecated "
+ "in C++20 and unsupported in C++2b">,
InGroup<DeprecatedCommaSubscript>;
def ext_subscript_non_lvalue : Extension<
@@ -8972,6 +8975,12 @@ def err_operator_overload_static : Error<
"overloaded %0 cannot be a static member function">;
def err_operator_overload_default_arg : Error<
"parameter of overloaded %0 cannot have a default argument">;
+
+def ext_subscript_overload : ExtWarn<
+ "overloaded %0 with %select{no|a defaulted|more than one}1 parameter is a C++2b extension">, InGroup<CXXPre2bCompat>, DefaultIgnore;
+def error_subscript_overload : Error<
+ "overloaded %0 cannot have %select{no|a defaulted|more than one}1 parameter before C++2b">;
+
def err_operator_overload_must_be : Error<
"overloaded %0 must be a %select{unary|binary|unary or binary}2 operator "
"(has %1 parameter%s1)">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 30148659562ed..e6a628f612ff3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3943,8 +3943,8 @@ class Sema final {
FunctionDecl *DefaultedFn);
ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
- SourceLocation RLoc,
- Expr *Base,Expr *Idx);
+ SourceLocation RLoc, Expr *Base,
+ MultiExprArg Args);
ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc,
@@ -5386,7 +5386,8 @@ class Sema final {
tok::TokenKind Kind, Expr *Input);
ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
- Expr *Idx, SourceLocation RLoc);
+ MultiExprArg ArgExprs,
+ SourceLocation RLoc);
ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc);
@@ -7434,10 +7435,16 @@ class Sema final {
CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
CXXRecordDecl *DecomposedClass,
DeclAccessPair Field);
+ AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr,
+ const SourceRange &,
+ DeclAccessPair FoundDecl);
AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
Expr *ObjectExpr,
Expr *ArgExpr,
DeclAccessPair FoundDecl);
+ AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr,
+ ArrayRef<Expr *> ArgExprs,
+ DeclAccessPair FoundDecl);
AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr,
DeclAccessPair FoundDecl);
AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index adc0720fe0008..746bf8c21cd72 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1736,21 +1736,16 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
}
} else if (Kind == OO_Arrow) {
PrintExpr(Node->getArg(0));
- } else if (Kind == OO_Call) {
+ } else if (Kind == OO_Call || Kind == OO_Subscript) {
PrintExpr(Node->getArg(0));
- OS << '(';
+ OS << (Kind == OO_Call ? '(' : '[');
for (unsigned ArgIdx = 1; ArgIdx < Node->getNumArgs(); ++ArgIdx) {
if (ArgIdx > 1)
OS << ", ";
if (!isa<CXXDefaultArgExpr>(Node->getArg(ArgIdx)))
PrintExpr(Node->getArg(ArgIdx));
}
- OS << ')';
- } else if (Kind == OO_Subscript) {
- PrintExpr(Node->getArg(0));
- OS << '[';
- PrintExpr(Node->getArg(1));
- OS << ']';
+ OS << (Kind == OO_Call ? ')' : ']');
} else if (Node->getNumArgs() == 1) {
OS << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(0));
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index e259ab47c5589..bf8a0b2abe22e 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -642,6 +642,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_implicit_move", "202011L");
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
Builder.defineMacro("__cpp_if_consteval", "202106L");
+ Builder.defineMacro("__cpp_multidimensional_subscript", "202110L");
}
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "201811L");
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index fbf79a0a8746d..3e8a6b9a7cb5d 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1835,6 +1835,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
/// primary-expression
/// postfix-expression '[' expression ']'
/// postfix-expression '[' braced-init-list ']'
+/// postfix-expression '[' expression-list [opt] ']' [C++2b 12.4.5]
/// postfix-expression '(' argument-expression-list[opt] ')'
/// postfix-expression '.' identifier
/// postfix-expression '->' identifier
@@ -1898,30 +1899,58 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
(void)Actions.CorrectDelayedTyposInExpr(LHS);
return ExprError();
}
-
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
Loc = T.getOpenLocation();
- ExprResult Idx, Length, Stride;
+ ExprResult Length, Stride;
SourceLocation ColonLocFirst, ColonLocSecond;
+ ExprVector ArgExprs;
+ bool HasError = false;
PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());
- if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
- Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
- Idx = ParseBraceInitializer();
- } else if (getLangOpts().OpenMP) {
- ColonProtectionRAIIObject RAII(*this);
- // Parse [: or [ expr or [ expr :
- if (!Tok.is(tok::colon)) {
- // [ expr
- Idx = ParseExpression();
+
+ // We try to parse a list of indexes in all language mode first
+ // and, in we find 0 or one index, we try to parse an OpenMP array
+ // section. This allow us to support C++2b multi dimensional subscript and
+ // OpenMp sections in the same language mode.
+ if (!getLangOpts().OpenMP || Tok.isNot(tok::colon)) {
+ if (!getLangOpts().CPlusPlus2b) {
+ ExprResult Idx;
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+ Idx = ParseBraceInitializer();
+ } else {
+ Idx = ParseExpression(); // May be a comma expression
+ }
+ LHS = Actions.CorrectDelayedTyposInExpr(LHS);
+ Idx = Actions.CorrectDelayedTyposInExpr(Idx);
+ if (Idx.isInvalid()) {
+ HasError = true;
+ } else {
+ ArgExprs.push_back(Idx.get());
+ }
+ } else if (Tok.isNot(tok::r_square)) {
+ CommaLocsTy CommaLocs;
+ if (ParseExpressionList(ArgExprs, CommaLocs)) {
+ LHS = Actions.CorrectDelayedTyposInExpr(LHS);
+ HasError = true;
+ }
+ assert(
+ (ArgExprs.empty() || ArgExprs.size() == CommaLocs.size() + 1) &&
+ "Unexpected number of commas!");
}
+ }
+
+ if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
+ ColonProtectionRAIIObject RAII(*this);
if (Tok.is(tok::colon)) {
// Consume ':'
ColonLocFirst = ConsumeToken();
if (Tok.isNot(tok::r_square) &&
(getLangOpts().OpenMP < 50 ||
- ((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50))))
+ ((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50)))) {
Length = ParseExpression();
+ Length = Actions.CorrectDelayedTyposInExpr(Length);
+ }
}
if (getLangOpts().OpenMP >= 50 &&
(OMPClauseKind == llvm::omp::Clause::OMPC_to ||
@@ -1933,27 +1962,23 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
Stride = ParseExpression();
}
}
- } else
- Idx = ParseExpression();
+ }
SourceLocation RLoc = Tok.getLocation();
-
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
- Idx = Actions.CorrectDelayedTyposInExpr(Idx);
- Length = Actions.CorrectDelayedTyposInExpr(Length);
- if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() &&
+
+ if (!LHS.isInvalid() && !HasError && !Length.isInvalid() &&
!Stride.isInvalid() && Tok.is(tok::r_square)) {
if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
LHS = Actions.ActOnOMPArraySectionExpr(
- LHS.get(), Loc, Idx.get(), ColonLocFirst, ColonLocSecond,
- Length.get(), Stride.get(), RLoc);
+ LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0],
+ ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc);
} else {
LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
- Idx.get(), RLoc);
+ ArgExprs, RLoc);
}
} else {
LHS = ExprError();
- Idx = ExprError();
}
// Match the ']'.
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 3f7b387ec9250..00d3efd19d7a2 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1761,14 +1761,11 @@ Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
return CheckAccess(*this, UseLoc, Entity);
}
-/// Checks access to an overloaded member operator, including
-/// conversion operators.
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Expr *ObjectExpr,
- Expr *ArgExpr,
+ const SourceRange &Range,
DeclAccessPair Found) {
- if (!getLangOpts().AccessControl ||
- Found.getAccess() == AS_public)
+ if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
return AR_accessible;
const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
@@ -1776,13 +1773,35 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
ObjectExpr->getType());
- Entity.setDiag(diag::err_access)
- << ObjectExpr->getSourceRange()
- << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
+ Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range;
return CheckAccess(*this, OpLoc, Entity);
}
+/// Checks access to an overloaded member operator, including
+/// conversion operators.
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ Expr *ArgExpr,
+ DeclAccessPair Found) {
+ return CheckMemberOperatorAccess(
+ OpLoc, ObjectExpr, ArgExpr ? ArgExpr->getSourceRange() : SourceRange(),
+ Found);
+}
+
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ ArrayRef<Expr *> ArgExprs,
+ DeclAccessPair FoundDecl) {
+ SourceRange R;
+ if (!ArgExprs.empty()) {
+ R = SourceRange(ArgExprs.front()->getBeginLoc(),
+ ArgExprs.back()->getEndLoc());
+ }
+
+ return CheckMemberOperatorAccess(OpLoc, ObjectExpr, R, FoundDecl);
+}
+
/// Checks access to the target of a friend declaration.
Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
assert(isa<CXXMethodDecl>(target->getAsFunction()));
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 16cdb7e577237..90a1cf514eb6e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -15865,14 +15865,29 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// An operator function cannot have default arguments (8.3.6),
// except where explicitly stated below.
//
- // Only the function-call operator allows default arguments
- // (C++ [over.call]p1).
+ // Only the function-call operator (C++ [over.call]p1) and the subscript
+ // operator (CWG2507) allow default arguments.
if (Op != OO_Call) {
+ ParmVarDecl *FirstDefaultedParam = nullptr;
for (auto Param : FnDecl->parameters()) {
- if (Param->hasDefaultArg())
- return Diag(Param->getLocation(),
+ if (Param->hasDefaultArg()) {
+ FirstDefaultedParam = Param;
+ break;
+ }
+ }
+ if (FirstDefaultedParam) {
+ if (Op == OO_Subscript) {
+ Diag(FnDecl->getLocation(), LangOpts.CPlusPlus2b
+ ? diag::ext_subscript_overload
+ : diag::error_subscript_overload)
+ << FnDecl->getDeclName() << 1
+ << FirstDefaultedParam->getDefaultArgRange();
+ } else {
+ return Diag(FirstDefaultedParam->getLocation(),
diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName() << Param->getDefaultArgRange();
+ << FnDecl->getDeclName()
+ << FirstDefaultedParam->getDefaultArgRange();
+ }
}
}
@@ -15893,10 +15908,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// described in the rest of this subclause.
unsigned NumParams = FnDecl->getNumParams()
+ (isa<CXXMethodDecl>(FnDecl)? 1 : 0);
- if (Op != OO_Call &&
+ if (Op != OO_Call && Op != OO_Subscript &&
((NumParams == 1 && !CanBeUnaryOperator) ||
- (NumParams == 2 && !CanBeBinaryOperator) ||
- (NumParams < 1) || (NumParams > 2))) {
+ (NumParams == 2 && !CanBeBinaryOperator) || (NumParams < 1) ||
+ (NumParams > 2))) {
// We have the wrong number of parameters.
unsigned ErrorKind;
if (CanBeUnaryOperator && CanBeBinaryOperator) {
@@ -15908,16 +15923,23 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
"All non-call overloaded operators are unary or binary!");
ErrorKind = 1; // 1 -> binary
}
-
return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be)
<< FnDecl->getDeclName() << NumParams << ErrorKind;
}
- // Overloaded operators other than operator() cannot be variadic.
+ if (Op == OO_Subscript && NumParams != 2) {
+ Diag(FnDecl->getLocation(), LangOpts.CPlusPlus2b
+ ? diag::ext_subscript_overload
+ : diag::error_subscript_overload)
+ << FnDecl->getDeclName() << (NumParams == 1 ? 0 : 2);
+ }
+
+ // Overloaded operators other than operator() and operator[] cannot be
+ // variadic.
if (Op != OO_Call &&
FnDecl->getType()->castAs<FunctionProtoType>()->isVariadic()) {
return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
- << FnDecl->getDeclName();
+ << FnDecl->getDeclName();
}
// Some operators must be non-static member functions.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 85553eccde835..6629f3e061f80 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4681,19 +4681,24 @@ static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS,
return Result->isDependentType() ? Result : Ctx.DependentTy;
}
-ExprResult
-Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
- Expr *idx, SourceLocation rbLoc) {
+static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args);
+
+ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
+ SourceLocation lbLoc,
+ MultiExprArg ArgExprs,
+ SourceLocation rbLoc) {
+
if (base && !base->getType().isNull() &&
base->hasPlaceholderType(BuiltinType::OMPArraySection))
- return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(),
+ return ActOnOMPArraySectionExpr(base, lbLoc, ArgExprs.front(), SourceLocation(),
SourceLocation(), /*Length*/ nullptr,
/*Stride=*/nullptr, 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();
+ if (result.isInvalid())
+ return ExprError();
base = result.get();
}
@@ -4721,13 +4726,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// MatrixSubscriptExpr.
auto *matSubscriptE = dyn_cast<MatrixSubscriptExpr>(base);
if (matSubscriptE) {
- if (CheckAndReportCommaError(idx))
+ assert(ArgExprs.size() == 1);
+ if (CheckAndReportCommaError(ArgExprs.front()))
return ExprError();
assert(matSubscriptE->isIncomplete() &&
"base has to be an incomplete matrix subscript");
- return CreateBuiltinMatrixSubscriptExpr(
- matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc);
+ return CreateBuiltinMatrixSubscriptExpr(matSubscriptE->getBase(),
+ matSubscriptE->getRowIdx(),
+ ArgExprs.front(), rbLoc);
}
// Handle any non-overload placeholder types in the base and index
@@ -4748,32 +4755,42 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// If the base is a matrix type, try to create a new MatrixSubscriptExpr.
if (base->getType()->isMatrixType()) {
- if (CheckAndReportCommaError(idx))
+ assert(ArgExprs.size() == 1);
+ if (CheckAndReportCommaError(ArgExprs.front()))
return ExprError();
- return CreateBuiltinMatrixSubscriptExpr(base, idx, nullptr, rbLoc);
+ return CreateBuiltinMatrixSubscriptExpr(base, ArgExprs.front(), nullptr,
+ rbLoc);
}
- // A comma-expression as the index is deprecated in C++2a onwards.
- if (getLangOpts().CPlusPlus20 &&
- ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
- (isa<CXXOperatorCallExpr>(idx) &&
- cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) {
- Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
- << SourceRange(base->getBeginLoc(), rbLoc);
+ if (ArgExprs.size() == 1 && getLangOpts().CPlusPlus20) {
+ Expr *idx = ArgExprs[0];
+ if ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
+ (isa<CXXOperatorCallExpr>(idx) &&
+ cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma)) {
+ Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ }
}
- if (idx->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(idx);
- if (result.isInvalid()) return ExprError();
- idx = result.get();
+ if (ArgExprs.size() == 1 &&
+ ArgExprs[0]->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(ArgExprs[0]);
+ if (result.isInvalid())
+ return ExprError();
+ ArgExprs[0] = result.get();
+ } else {
+ if (checkArgsForPlaceholders(*this, ArgExprs))
+ return ExprError();
}
// Build an unanalyzed expression if either operand is type-dependent.
- if (getLangOpts().CPlusPlus &&
- (base->isTypeDependent() || idx->isTypeDependent())) {
+ if (getLangOpts().CPlusPlus && ArgExprs.size() == 1 &&
+ (base->isTypeDependent() ||
+ Expr::hasAnyTypeDependentArguments(ArgExprs))) {
return new (Context) ArraySubscriptExpr(
- base, idx, getDependentArraySubscriptType(base, idx, getASTContext()),
+ base, ArgExprs.front(),
+ getDependentArraySubscriptType(base, ArgExprs.front(), getASTContext()),
VK_LValue, OK_Ordinary, rbLoc);
}
@@ -4786,10 +4803,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b),
// and p->x[a][b] = i will be turned into p->PutX(a, b, i);
if (IsMSPropertySubscript) {
+ assert(ArgExprs.size() == 1);
// Build MS property subscript expression if base is MS property reference
// or MS property subscript.
- return new (Context) MSPropertySubscriptExpr(
- base, idx, Context.PseudoObjectTy, VK_LValue, OK_Ordinary, rbLoc);
+ return new (Context)
+ MSPropertySubscriptExpr(base, ArgExprs.front(), Context.PseudoObjectTy,
+ VK_LValue, OK_Ordinary, rbLoc);
}
// Use C++ overloaded-operator rules if either operand has record
@@ -4800,14 +4819,14 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
//
// ObjC pointers have their own subscripting logic that is not tied
// to overload resolution and so should not take this path.
- if (getLangOpts().CPlusPlus &&
- (base->getType()->isRecordType() ||
- (!base->getType()->isObjCObjectPointerType() &&
- idx->getType()->isRecordType()))) {
- return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx);
+ if (getLangOpts().CPlusPlus && !base->getType()->isObjCObjectPointerType() &&
+ ((base->getType()->isRecordType() ||
+ (ArgExprs.size() != 1 || ArgExprs[0]->getType()->isRecordType())))) {
+ return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, ArgExprs);
}
- ExprResult Res = CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
+ ExprResult Res =
+ CreateBuiltinArraySubscriptExpr(base, lbLoc, ArgExprs.front(), rbLoc);
if (!Res.isInvalid() && isa<ArraySubscriptExpr>(Res.get()))
CheckSubscriptAccessOfNoDeref(cast<ArraySubscriptExpr>(Res.get()));
@@ -6582,9 +6601,9 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
auto ArgAS = ArgPtTy.getAddressSpace();
// Add address space cast if target address spaces are
diff erent
- bool NeedImplicitASC =
+ bool NeedImplicitASC =
ParamAS != LangAS::Default && // Pointer params in generic AS don't need special handling.
- ( ArgAS == LangAS::Default || // We do allow implicit conversion from generic AS
+ ( ArgAS == LangAS::Default || // We do allow implicit conversion from generic AS
// or from specific AS which has target AS matching that of Param.
getASTContext().getTargetAddressSpace(ArgAS) == getASTContext().getTargetAddressSpace(ParamAS));
if (!NeedImplicitASC)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 3fa192cedfa38..6167526f8096d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -49,11 +49,10 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
}
/// A convenience routine for creating a decayed reference to a function.
-static ExprResult
-CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
- const Expr *Base, bool HadMultipleCandidates,
- SourceLocation Loc = SourceLocation(),
- const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
+static ExprResult CreateFunctionRefExpr(
+ Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, const Expr *Base,
+ bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(),
+ const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) {
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
return ExprError();
// If FoundDecl is
diff erent from Fn (such as if one is a template
@@ -984,8 +983,7 @@ checkPlaceholderForOverload(Sema &S, Expr *&E,
/// checkArgPlaceholdersForOverload - Check a set of call operands for
/// placeholders.
-static bool checkArgPlaceholdersForOverload(Sema &S,
- MultiExprArg Args,
+static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args,
UnbridgedCastsSet &unbridged) {
for (unsigned i = 0, e = Args.size(); i != e; ++i)
if (checkPlaceholderForOverload(S, Args[i], &unbridged))
@@ -9352,7 +9350,8 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
break;
case OO_Subscript:
- OpBuilder.addSubscriptOverloads();
+ if (Args.size() == 2)
+ OpBuilder.addSubscriptOverloads();
break;
case OO_ArrowStar:
@@ -11617,7 +11616,9 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
if (CSK == OverloadCandidateSet::CSK_Operator &&
- Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call)
+ Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call &&
+ Cand->Function->getDeclName().getCXXOverloadedOperator() !=
+ OO_Subscript)
// Argument 0 is 'this', which doesn't have a corresponding parameter.
ArgIdx = 1;
}
@@ -14055,17 +14056,65 @@ ExprResult Sema::BuildSynthesizedThreeWayComparison(
return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2);
}
-ExprResult
-Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
- SourceLocation RLoc,
- Expr *Base, Expr *Idx) {
- Expr *Args[2] = { Base, Idx };
+static bool PrepareArgumentsForCallToObjectOfClassType(
+ Sema &S, SmallVectorImpl<Expr *> &MethodArgs, CXXMethodDecl *Method,
+ MultiExprArg Args, SourceLocation LParenLoc) {
+
+ const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
+ unsigned NumParams = Proto->getNumParams();
+ unsigned NumArgsSlots =
+ MethodArgs.size() + std::max<unsigned>(Args.size(), NumParams);
+ // Build the full argument list for the method call (the implicit object
+ // parameter is placed at the beginning of the list).
+ MethodArgs.reserve(MethodArgs.size() + NumArgsSlots);
+ bool IsError = false;
+ // Initialize the implicit object parameter.
+ // Check the argument types.
+ for (unsigned i = 0; i != NumParams; i++) {
+ Expr *Arg;
+ if (i < Args.size()) {
+ Arg = Args[i];
+ ExprResult InputInit =
+ S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ S.Context, Method->getParamDecl(i)),
+ SourceLocation(), Arg);
+ IsError |= InputInit.isInvalid();
+ Arg = InputInit.getAs<Expr>();
+ } else {
+ ExprResult DefArg =
+ S.BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
+ if (DefArg.isInvalid()) {
+ IsError = true;
+ break;
+ }
+ Arg = DefArg.getAs<Expr>();
+ }
+
+ MethodArgs.push_back(Arg);
+ }
+ return IsError;
+}
+
+ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
+ SourceLocation RLoc,
+ Expr *Base,
+ MultiExprArg ArgExpr) {
+ SmallVector<Expr *, 2> Args;
+ Args.push_back(Base);
+ for (auto e : ArgExpr) {
+ Args.push_back(e);
+ }
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Subscript);
+ SourceRange Range = ArgExpr.empty()
+ ? SourceRange{}
+ : SourceRange(ArgExpr.front()->getBeginLoc(),
+ ArgExpr.back()->getEndLoc());
+
// If either side is type-dependent, create an appropriate dependent
// expression.
- if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
+ if (Expr::hasAnyTypeDependentArguments(Args)) {
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
// CHECKME: no 'operator' keyword?
@@ -14082,12 +14131,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
CurFPFeatureOverrides());
}
- // Handle placeholders on both operands.
- if (checkPlaceholderForOverload(*this, Args[0]))
- return ExprError();
- if (checkPlaceholderForOverload(*this, Args[1]))
+ // Handle placeholders
+ UnbridgedCastsSet UnbridgedCasts;
+ if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) {
return ExprError();
-
+ }
// Build an empty overload set.
OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
@@ -14097,7 +14145,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
// Add builtin operator candidates.
- AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
+ if (Args.size() == 2)
+ AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -14112,38 +14161,28 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
+ CheckMemberOperatorAccess(LLoc, Args[0], ArgExpr, Best->FoundDecl);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- ExprResult Arg0 =
- PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
- Best->FoundDecl, Method);
+ SmallVector<Expr *, 2> MethodArgs;
+ ExprResult Arg0 = PerformObjectArgumentInitialization(
+ Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
- Args[0] = Arg0.get();
- // Convert the arguments.
- ExprResult InputInit
- = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- FnDecl->getParamDecl(0)),
- SourceLocation(),
- Args[1]);
- if (InputInit.isInvalid())
+ MethodArgs.push_back(Arg0.get());
+ bool IsError = PrepareArgumentsForCallToObjectOfClassType(
+ *this, MethodArgs, Method, ArgExpr, LLoc);
+ if (IsError)
return ExprError();
- Args[1] = InputInit.getAs<Expr>();
-
// Build the actual expression node.
DeclarationNameInfo OpLocInfo(OpName, LLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
- Best->FoundDecl,
- Base,
- HadMultipleCandidates,
- OpLocInfo.getLoc(),
- OpLocInfo.getInfo());
+ ExprResult FnExpr = CreateFunctionRefExpr(
+ *this, FnDecl, Best->FoundDecl, Base, HadMultipleCandidates,
+ OpLocInfo.getLoc(), OpLocInfo.getInfo());
if (FnExpr.isInvalid())
return ExprError();
@@ -14153,7 +14192,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Subscript, FnExpr.get(), Args, ResultTy, VK, RLoc,
+ Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
CurFPFeatureOverrides());
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
@@ -14187,33 +14226,41 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
case OR_No_Viable_Function: {
- PartialDiagnostic PD = CandidateSet.empty()
- ? (PDiag(diag::err_ovl_no_oper)
- << Args[0]->getType() << /*subscript*/ 0
- << Args[0]->getSourceRange() << Args[1]->getSourceRange())
- : (PDiag(diag::err_ovl_no_viable_subscript)
- << Args[0]->getType() << Args[0]->getSourceRange()
- << Args[1]->getSourceRange());
+ PartialDiagnostic PD =
+ CandidateSet.empty()
+ ? (PDiag(diag::err_ovl_no_oper)
+ << Args[0]->getType() << /*subscript*/ 0
+ << Args[0]->getSourceRange() << Range)
+ : (PDiag(diag::err_ovl_no_viable_subscript)
+ << Args[0]->getType() << Args[0]->getSourceRange() << Range);
CandidateSet.NoteCandidates(PartialDiagnosticAt(LLoc, PD), *this,
- OCD_AllCandidates, Args, "[]", LLoc);
+ OCD_AllCandidates, ArgExpr, "[]", LLoc);
return ExprError();
}
case OR_Ambiguous:
- CandidateSet.NoteCandidates(
- PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
- << "[]" << Args[0]->getType()
- << Args[1]->getType()
- << Args[0]->getSourceRange()
- << Args[1]->getSourceRange()),
- *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
+ if (Args.size() == 2) {
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
+ << "[]" << Args[0]->getType() << Args[1]->getType()
+ << Args[0]->getSourceRange() << Range),
+ *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
+ } else {
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(LLoc,
+ PDiag(diag::err_ovl_ambiguous_subscript_call)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange() << Range),
+ *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
+ }
return ExprError();
case OR_Deleted:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_deleted_oper)
<< "[]" << Args[0]->getSourceRange()
- << Args[1]->getSourceRange()),
+ << Range),
*this, OCD_AllCandidates, Args, "[]", LLoc);
return ExprError();
}
@@ -14717,14 +14764,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (NewFn.isInvalid())
return true;
- // The number of argument slots to allocate in the call. If we have default
- // arguments we need to allocate space for them as well. We additionally
- // need one more slot for the object parameter.
- unsigned NumArgsSlots = 1 + std::max<unsigned>(Args.size(), NumParams);
-
- // Build the full argument list for the method call (the implicit object
- // parameter is placed at the beginning of the list).
- SmallVector<Expr *, 8> MethodArgs(NumArgsSlots);
+ SmallVector<Expr *, 8> MethodArgs;
+ MethodArgs.reserve(NumParams + 1);
bool IsError = false;
@@ -14736,37 +14777,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
IsError = true;
else
Object = ObjRes;
- MethodArgs[0] = Object.get();
-
- // Check the argument types.
- for (unsigned i = 0; i != NumParams; i++) {
- Expr *Arg;
- if (i < Args.size()) {
- Arg = Args[i];
-
- // Pass the argument.
-
- ExprResult InputInit
- = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- Method->getParamDecl(i)),
- SourceLocation(), Arg);
-
- IsError |= InputInit.isInvalid();
- Arg = InputInit.getAs<Expr>();
- } else {
- ExprResult DefArg
- = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
- if (DefArg.isInvalid()) {
- IsError = true;
- break;
- }
+ MethodArgs.push_back(Object.get());
- Arg = DefArg.getAs<Expr>();
- }
-
- MethodArgs[i + 1] = Arg;
- }
+ IsError |= PrepareArgumentsForCallToObjectOfClassType(
+ *this, MethodArgs, Method, Args, LParenLoc);
// If this is a variadic call, handle args passed through "...".
if (Proto->isVariadic()) {
@@ -14775,7 +14789,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
nullptr);
IsError |= Arg.isInvalid();
- MethodArgs[i + 1] = Arg.get();
+ MethodArgs.push_back(Arg.get());
}
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5c37fcaaea13d..facb4f3a49448 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2629,6 +2629,13 @@ class TreeTransform {
/*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc, ExecConfig);
}
+ ExprResult RebuildCxxSubscriptExpr(Expr *Callee, SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnArraySubscriptExpr(
+ /*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc);
+ }
+
/// Build a new member access expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -11507,6 +11514,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
case OO_Array_Delete:
llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr");
+ case OO_Subscript:
case OO_Call: {
// This is a call to an object's operator().
assert(E->getNumArgs() >= 1 && "Object call is missing arguments");
@@ -11526,17 +11534,20 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
Args))
return ExprError();
+ if (E->getOperator() == OO_Subscript)
+ return getDerived().RebuildCxxSubscriptExpr(Object.get(), FakeLParenLoc,
+ Args, E->getEndLoc());
+
return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc, Args,
E->getEndLoc());
}
-#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- case OO_##Name:
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
+ case OO_##Name: \
+ break;
+
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
#include "clang/Basic/OperatorKinds.def"
- case OO_Subscript:
- // Handled below.
- break;
case OO_Conditional:
llvm_unreachable("conditional operator is not actually overloadable");
diff --git a/clang/test/OpenMP/target_update_messages.cpp b/clang/test/OpenMP/target_update_messages.cpp
index 8a27e2d623840..fd9d5455c9f1e 100644
--- a/clang/test/OpenMP/target_update_messages.cpp
+++ b/clang/test/OpenMP/target_update_messages.cpp
@@ -6,6 +6,8 @@
// RUN: %clang_cc1 -verify=expected,ge50,lt51 -fopenmp-simd -fopenmp-version=50 -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
// RUN: %clang_cc1 -verify=expected,ge50,ge51 -fopenmp-simd -fopenmp-version=51 -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,ge50,ge51,cxx2b -fopenmp -fopenmp-simd -fopenmp-version=51 -x c++ -std=c++2b %s -Wuninitialized
+
void xxx(int argc) {
int x; // expected-note {{initialize the variable 'x' to silence this warning}}
#pragma omp target update to(x)
@@ -209,3 +211,43 @@ struct bar {
foo();
}
};
+
+#if defined(__cplusplus) && __cplusplus >= 202101L
+
+namespace cxx2b {
+
+struct S {
+ int operator[](auto...);
+};
+
+void f() {
+
+ int test[10];
+
+#pragma omp target update to(test[1])
+
+#pragma omp target update to(test[1, 2]) // cxx2b-error {{type 'int[10]' does not provide a subscript operator}} \
+ // cxx2b-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+
+#pragma omp target update to(test [1:1:1])
+
+#pragma omp target update to(test [1, 2:1:1]) // cxx2b-error {{expected ']'}} // expected-note {{'['}} \
+ // cxx2b-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+
+#pragma omp target update to(test [1, 2:]) // cxx2b-error {{expected ']'}} // expected-note {{'['}} \
+ // cxx2b-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+
+#pragma omp target update to(test[1, 2 ::]) // cxx2b-error {{expected ']'}} // expected-note {{'['}} \
+ // cxx2b-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+
+#pragma omp target update to(test[]) // cxx2b-error {{type 'int[10]' does not provide a subscript operator}} \
+ // cxx2b-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+ S s;
+ (void)s[0];
+ (void)s[];
+ (void)s[1, 2];
+}
+
+}
+
+#endif
diff --git a/clang/test/Parser/cxx2b-subscript.cpp b/clang/test/Parser/cxx2b-subscript.cpp
new file mode 100644
index 0000000000000..c56df48a379d9
--- /dev/null
+++ b/clang/test/Parser/cxx2b-subscript.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+//cxx2b-no-diagnostics
+
+struct S {
+ constexpr int operator[](int i) {
+ return i;
+ }
+ constexpr int operator[](int a, int b) { // cxx20-error {{overloaded 'operator[]' cannot have more than one parameter before C++2b}}
+ return a + b;
+ }
+ constexpr int operator[]() { // cxx20-error {{overloaded 'operator[]' cannot have no parameter before C++2b}}
+ return 42;
+ }
+};
+
+struct Defaults {
+ constexpr int operator[](int i = 0) { // cxx20-error {{overloaded 'operator[]' cannot have a defaulted parameter before C++2b}}
+ return 0;
+ }
+ constexpr int operator[](int a, int b, int c = 0) { // cxx20-error {{overloaded 'operator[]' cannot have a defaulted parameter before C++2b}}\
+ // cxx20-error {{cannot have more than one parameter before C++2b}}
+ return 0;
+ }
+};
+
+template <typename... T>
+struct T1 {
+ constexpr auto operator[](T &&...arg); // cxx20-error {{overloaded 'operator[]' cannot have no parameter before C++2b}} \
+ // cxx20-error {{overloaded 'operator[]' cannot have more than one parameter before C++2b}}
+};
+
+T1<> t10; // cxx20-note {{requested here}}
+T1<int, int> t12; // cxx20-note {{requested here}}
+T1<int> t11;
+
+struct Variadic {
+ constexpr int operator[](auto &&...arg) { return 0; }
+};
+
+void f() {
+ S s;
+ (void)s[0];
+ (void)s[1, 2]; // cxx20-warning {{left operand of comma operator has no effect}}\
+ // cxx20-warning {{top-level comma expression in array subscript is deprecated in C++20 and unsupported in C++2b}}
+ (void)S{}[]; // cxx20-error {{expected expression}}
+
+ (void)Defaults{}[1];
+ (void)Defaults{}[]; // cxx20-error {{expected expression}}
+ (void)Defaults{}[1, 2]; // cxx20-warning {{left operand of comma operator has no effect}}\
+ // cxx20-warning {{top-level comma expression in array subscript is deprecated in C++20 and unsupported in C++2b}}
+
+ Variadic{}[]; // cxx20-error {{expected expression}}
+ Variadic{}[1];
+ Variadic{}[1, 2]; // cxx20-warning {{left operand of comma operator has no effect}}\
+ // cxx20-warning {{top-level comma expression in array subscript is deprecated in C++20 and unsupported in C++2b}}
+}
diff --git a/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp b/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp
new file mode 100644
index 0000000000000..f9a83c813dcf0
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2b-overloaded-operator.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -verify -std=c++2b %s
+
+namespace N {
+
+void empty() {
+ struct S {
+ int operator[](); // expected-note{{not viable: requires 0 arguments, but 1 was provided}}
+ };
+
+ S{}[];
+ S{}[1]; // expected-error {{no viable overloaded operator[] for type 'S'}}
+}
+
+void default_var() {
+ struct S {
+ constexpr int operator[](int i = 42) { return i; } // expected-note {{not viable: allows at most single argument 'i'}}
+ };
+ static_assert(S{}[] == 42);
+ static_assert(S{}[1] == 1);
+ static_assert(S{}[1, 2] == 1); // expected-error {{no viable overloaded operator[] for type 'S'}}
+}
+
+struct Variadic {
+ constexpr int operator[](auto... i) { return (42 + ... + i); }
+};
+
+void variadic() {
+
+ static_assert(Variadic{}[] == 42);
+ static_assert(Variadic{}[1] == 43);
+ static_assert(Variadic{}[1, 2] == 45);
+}
+
+void multiple() {
+ struct S {
+ constexpr int operator[]() { return 0; }
+ constexpr int operator[](int) { return 1; };
+ constexpr int operator[](int, int) { return 2; };
+ };
+ static_assert(S{}[] == 0);
+ static_assert(S{}[1] == 1);
+ static_assert(S{}[1, 1] == 2);
+}
+
+void ambiguous() {
+ struct S {
+ constexpr int operator[]() { return 0; } // expected-note{{candidate function}}
+ constexpr int operator[](int = 0) { return 1; }; // expected-note{{candidate function}}
+ };
+
+ static_assert(S{}[] == 0); // expected-error{{call to subscript operator of type 'S' is ambiguous}}
+}
+} // namespace N
+
+template <typename... T>
+struct T1 {
+ constexpr auto operator[](T... arg) { // expected-note {{candidate function not viable: requires 2 arguments, but 1 was provided}}
+ return (1 + ... + arg);
+ }
+};
+
+static_assert(T1<>{}[] == 1);
+static_assert(T1<int>{}[1] == 2);
+static_assert(T1<int, int>{}[1, 1] == 3);
+static_assert(T1<int, int>{}[1] == 3); // expected-error {{no viable overloaded operator[] for type 'T1<int, int>'}}
+
+struct T2 {
+ constexpr auto operator[](auto... arg) {
+ return (1 + ... + arg);
+ }
+};
+
+static_assert(T2{}[] == 1);
+static_assert(T2{}[1] == 2);
+static_assert(T2{}[1, 1] == 3);
diff --git a/clang/test/SemaTemplate/instantiate-subscript.cpp b/clang/test/SemaTemplate/instantiate-subscript.cpp
index 8c119ec8c6de8..3015f720cf1f1 100644
--- a/clang/test/SemaTemplate/instantiate-subscript.cpp
+++ b/clang/test/SemaTemplate/instantiate-subscript.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2b %s
struct Sub0 {
int &operator[](int);
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index c4acd8d30ddb5..7a6cdba840e23 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1356,7 +1356,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
<tr>
<td>Multidimensional subscript operator</td>
<td><a href="https://wg21.link/P2128R6">P2128R6</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 15</td>
</tr>
<tr>
<td>Non-literal variables (and labels and gotos) in constexpr functions</td>
More information about the cfe-commits
mailing list