diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 41bec2666f939..6e3d566d55948 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -288,6 +288,10 @@ Improvements to Clang's diagnostics - Fixed a bug where the source location was missing when diagnosing ill-formed placeholder constraints. +- The two-element, unary mask variant of ``__builtin_shufflevector`` is now + properly being rejected when used at compile-time. It was not implemented + and caused assertion failures before (#GH158471). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 78b74acc3789d..99f4bfbea973d 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -3986,6 +3986,10 @@ bool Compiler::VisitConvertVectorExpr(const ConvertVectorExpr *E) { template bool Compiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { + // FIXME: Unary shuffle with mask not currently supported. + if (E->getNumSubExprs() == 2) + return this->emitInvalid(E); + assert(Initializing); assert(E->getNumSubExprs() > 2); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 820b053057067..f80691f57e602 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12160,6 +12160,9 @@ static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E, } bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { + // FIXME: Unary shuffle with mask not currently supported. + if (E->getNumSubExprs() == 2) + return Error(E); APValue VecVal1; const Expr *Vec1 = E->getExpr(0); if (!EvaluateAsRValue(Info, Vec1, VecVal1)) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 077f4311ed729..f62c82e3d214f 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5558,17 +5558,18 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) { /// BuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { - if (TheCall->getNumArgs() < 2) + unsigned NumArgs = TheCall->getNumArgs(); + if (NumArgs < 2) return ExprError(Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) - << 0 /*function call*/ << 2 << TheCall->getNumArgs() + << 0 /*function call*/ << 2 << NumArgs << /*is non object*/ 0 << TheCall->getSourceRange()); // Determine which of the following types of shufflevector we're checking: // 1) unary, vector mask: (lhs, mask) // 2) binary, scalar mask: (lhs, rhs, index, ..., index) - QualType resType = TheCall->getArg(0)->getType(); - unsigned numElements = 0; + QualType ResType = TheCall->getArg(0)->getType(); + unsigned NumElements = 0; if (!TheCall->getArg(0)->isTypeDependent() && !TheCall->getArg(1)->isTypeDependent()) { @@ -5578,43 +5579,43 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { if (!LHSType->isVectorType() || !RHSType->isVectorType()) return ExprError( Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false + << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ false << SourceRange(TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); - numElements = LHSType->castAs()->getNumElements(); - unsigned numResElements = TheCall->getNumArgs() - 2; + NumElements = LHSType->castAs()->getNumElements(); + unsigned NumResElements = NumArgs - 2; // Check to see if we have a call with 2 vector arguments, the unary shuffle // with mask. If so, verify that RHS is an integer vector type with the // same number of elts as lhs. - if (TheCall->getNumArgs() == 2) { + if (NumArgs == 2) { if (!RHSType->hasIntegerRepresentation() || - RHSType->castAs()->getNumElements() != numElements) + RHSType->castAs()->getNumElements() != NumElements) return ExprError(Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() - << /*isMorethantwoArgs*/ false + << /*isMoreThanTwoArgs*/ false << SourceRange(TheCall->getArg(1)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { return ExprError(Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() - << /*isMorethantwoArgs*/ false + << /*isMoreThanTwoArgs*/ false << SourceRange(TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); - } else if (numElements != numResElements) { - QualType eltType = LHSType->castAs()->getElementType(); - resType = resType->isExtVectorType() - ? Context.getExtVectorType(eltType, numResElements) - : Context.getVectorType(eltType, numResElements, + } else if (NumElements != NumResElements) { + QualType EltType = LHSType->castAs()->getElementType(); + ResType = ResType->isExtVectorType() + ? Context.getExtVectorType(EltType, NumResElements) + : Context.getVectorType(EltType, NumResElements, VectorKind::Generic); } } - for (unsigned i = 2; i < TheCall->getNumArgs(); i++) { - Expr *Arg = TheCall->getArg(i); + for (unsigned I = 2; I != NumArgs; ++I) { + Expr *Arg = TheCall->getArg(I); if (Arg->isTypeDependent() || Arg->isValueDependent()) continue; @@ -5628,23 +5629,21 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { if (Result->isSigned() && Result->isAllOnes()) ; else if (Result->getActiveBits() > 64 || - Result->getZExtValue() >= numElements * 2) + Result->getZExtValue() >= NumElements * 2) return ExprError(Diag(TheCall->getBeginLoc(), diag::err_shufflevector_argument_too_large) << Arg->getSourceRange()); - TheCall->setArg(i, ConstantExpr::Create(Context, Arg, APValue(*Result))); + TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result))); } - SmallVector exprs; - for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { - exprs.push_back(TheCall->getArg(i)); - TheCall->setArg(i, nullptr); - } + auto *Result = new (Context) ShuffleVectorExpr( + Context, ArrayRef(TheCall->getArgs(), NumArgs), ResType, + TheCall->getCallee()->getBeginLoc(), TheCall->getRParenLoc()); - return new (Context) ShuffleVectorExpr(Context, exprs, resType, - TheCall->getCallee()->getBeginLoc(), - TheCall->getRParenLoc()); + // All moved to Result. + TheCall->shrinkNumArgs(0); + return Result; } ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp index 714a7fb753214..455284ef65e9b 100644 --- a/clang/test/Sema/constant-builtins-vector.cpp +++ b/clang/test/Sema/constant-builtins-vector.cpp @@ -731,6 +731,19 @@ permitted in a constexpr context}} vector4charConst1, vector4charConst2, -1, -1, -1, -1); +namespace UnaryShuffleUnsupported { + typedef int vi6 __attribute__((ext_vector_type(2))); + constexpr int foo() { // expected-error {{never produces a constant expression}} + vi6 a = {1,2}; + vi6 b = {3,4}; + vi6 r = __builtin_shufflevector(a, b); // expected-note 2{{subexpression not valid in a constant expression}} + + return r[0] + r[1]; + } + static_assert(foo() == 0); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to}} +} + static_assert(__builtin_reduce_add((vector4char){}) == 0); static_assert(__builtin_reduce_add((vector4char){1, 2, 3, 4}) == 10); static_assert(__builtin_reduce_add((vector4short){10, 20, 30, 40}) == 100);