forked from OSchip/llvm-project
[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.
This commit is contained in:
parent
caf7f05c1c
commit
c151225096
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
------------------------------
|
||||
|
||||
|
|
|
@ -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)">;
|
||||
|
|
|
@ -3943,8 +3943,8 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 ']'.
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 different
|
||||
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)
|
||||
|
|
|
@ -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 different 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]))
|
||||
// Handle placeholders
|
||||
UnbridgedCastsSet UnbridgedCasts;
|
||||
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) {
|
||||
return ExprError();
|
||||
if (checkPlaceholderForOverload(*this, Args[1]))
|
||||
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();
|
||||
MethodArgs.push_back(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;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2629,6 +2629,13 @@ public:
|
|||
/*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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
|
@ -1356,7 +1356,7 @@ C++20, informally referred to as C++2b.</p>
|
|||
<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>
|
||||
|
|
Loading…
Reference in New Issue