diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /clang/lib/Sema/SemaChecking.cpp | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Vendor import of llvm-project main llvmorg-15-init-15358-g53dc0f107877.vendor/llvm-project/llvmorg-15-init-15358-g53dc0f107877
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 749 |
1 files changed, 613 insertions, 136 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index dfbf4cdc89cb..79420cc27699 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -109,24 +109,38 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, Context.getTargetInfo()); } +/// Checks that a call expression's argument count is at least the desired +/// number. This is useful when doing custom type-checking on a variadic +/// function. Returns true on error. +static bool checkArgCountAtLeast(Sema &S, CallExpr *Call, + unsigned MinArgCount) { + unsigned ArgCount = Call->getNumArgs(); + if (ArgCount >= MinArgCount) + return false; + + return S.Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args) + << 0 /*function call*/ << MinArgCount << ArgCount + << Call->getSourceRange(); +} + /// Checks that a call expression's argument count is the desired number. /// This is useful when doing custom type-checking. Returns true on error. -static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { - unsigned argCount = call->getNumArgs(); - if (argCount == desiredArgCount) return false; +static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) { + unsigned ArgCount = Call->getNumArgs(); + if (ArgCount == DesiredArgCount) + return false; - if (argCount < desiredArgCount) - return S.Diag(call->getEndLoc(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/ << desiredArgCount << argCount - << call->getSourceRange(); + if (checkArgCountAtLeast(S, Call, DesiredArgCount)) + return true; + assert(ArgCount > DesiredArgCount && "should have diagnosed this"); // Highlight all the excess arguments. - SourceRange range(call->getArg(desiredArgCount)->getBeginLoc(), - call->getArg(argCount - 1)->getEndLoc()); + SourceRange Range(Call->getArg(DesiredArgCount)->getBeginLoc(), + Call->getArg(ArgCount - 1)->getEndLoc()); - return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << desiredArgCount << argCount - << call->getArg(1)->getSourceRange(); + return S.Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << DesiredArgCount << ArgCount + << Call->getArg(1)->getSourceRange(); } /// Check that the first argument to __builtin_annotation is an integer @@ -147,7 +161,7 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { // Second argument should be a constant string. Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts(); StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg); - if (!Literal || !Literal->isAscii()) { + if (!Literal || !Literal->isOrdinary()) { S.Diag(StrArg->getBeginLoc(), diag::err_builtin_annotation_second_arg) << StrArg->getSourceRange(); return true; @@ -366,6 +380,311 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall, return false; } +namespace { +struct BuiltinDumpStructGenerator { + Sema &S; + CallExpr *TheCall; + SourceLocation Loc = TheCall->getBeginLoc(); + SmallVector<Expr *, 32> Actions; + DiagnosticErrorTrap ErrorTracker; + PrintingPolicy Policy; + + BuiltinDumpStructGenerator(Sema &S, CallExpr *TheCall) + : S(S), TheCall(TheCall), ErrorTracker(S.getDiagnostics()), + Policy(S.Context.getPrintingPolicy()) { + Policy.AnonymousTagLocations = false; + } + + Expr *makeOpaqueValueExpr(Expr *Inner) { + auto *OVE = new (S.Context) + OpaqueValueExpr(Loc, Inner->getType(), Inner->getValueKind(), + Inner->getObjectKind(), Inner); + Actions.push_back(OVE); + return OVE; + } + + Expr *getStringLiteral(llvm::StringRef Str) { + Expr *Lit = S.Context.getPredefinedStringLiteralFromCache(Str); + // Wrap the literal in parentheses to attach a source location. + return new (S.Context) ParenExpr(Loc, Loc, Lit); + } + + bool callPrintFunction(llvm::StringRef Format, + llvm::ArrayRef<Expr *> Exprs = {}) { + SmallVector<Expr *, 8> Args; + assert(TheCall->getNumArgs() >= 2); + Args.reserve((TheCall->getNumArgs() - 2) + /*Format*/ 1 + Exprs.size()); + Args.assign(TheCall->arg_begin() + 2, TheCall->arg_end()); + Args.push_back(getStringLiteral(Format)); + Args.insert(Args.end(), Exprs.begin(), Exprs.end()); + + // Register a note to explain why we're performing the call. + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::BuildingBuiltinDumpStructCall; + Ctx.PointOfInstantiation = Loc; + Ctx.CallArgs = Args.data(); + Ctx.NumCallArgs = Args.size(); + S.pushCodeSynthesisContext(Ctx); + + ExprResult RealCall = + S.BuildCallExpr(/*Scope=*/nullptr, TheCall->getArg(1), + TheCall->getBeginLoc(), Args, TheCall->getRParenLoc()); + + S.popCodeSynthesisContext(); + if (!RealCall.isInvalid()) + Actions.push_back(RealCall.get()); + // Bail out if we've hit any errors, even if we managed to build the + // call. We don't want to produce more than one error. + return RealCall.isInvalid() || ErrorTracker.hasErrorOccurred(); + } + + Expr *getIndentString(unsigned Depth) { + if (!Depth) + return nullptr; + + llvm::SmallString<32> Indent; + Indent.resize(Depth * Policy.Indentation, ' '); + return getStringLiteral(Indent); + } + + Expr *getTypeString(QualType T) { + return getStringLiteral(T.getAsString(Policy)); + } + + bool appendFormatSpecifier(QualType T, llvm::SmallVectorImpl<char> &Str) { + llvm::raw_svector_ostream OS(Str); + + // Format 'bool', 'char', 'signed char', 'unsigned char' as numbers, rather + // than trying to print a single character. + if (auto *BT = T->getAs<BuiltinType>()) { + switch (BT->getKind()) { + case BuiltinType::Bool: + OS << "%d"; + return true; + case BuiltinType::Char_U: + case BuiltinType::UChar: + OS << "%hhu"; + return true; + case BuiltinType::Char_S: + case BuiltinType::SChar: + OS << "%hhd"; + return true; + default: + break; + } + } + + analyze_printf::PrintfSpecifier Specifier; + if (Specifier.fixType(T, S.getLangOpts(), S.Context, /*IsObjCLiteral=*/false)) { + // We were able to guess how to format this. + if (Specifier.getConversionSpecifier().getKind() == + analyze_printf::PrintfConversionSpecifier::sArg) { + // Wrap double-quotes around a '%s' specifier and limit its maximum + // length. Ideally we'd also somehow escape special characters in the + // contents but printf doesn't support that. + // FIXME: '%s' formatting is not safe in general. + OS << '"'; + Specifier.setPrecision(analyze_printf::OptionalAmount(32u)); + Specifier.toString(OS); + OS << '"'; + // FIXME: It would be nice to include a '...' if the string doesn't fit + // in the length limit. + } else { + Specifier.toString(OS); + } + return true; + } + + if (T->isPointerType()) { + // Format all pointers with '%p'. + OS << "%p"; + return true; + } + + return false; + } + + bool dumpUnnamedRecord(const RecordDecl *RD, Expr *E, unsigned Depth) { + Expr *IndentLit = getIndentString(Depth); + Expr *TypeLit = getTypeString(S.Context.getRecordType(RD)); + if (IndentLit ? callPrintFunction("%s%s", {IndentLit, TypeLit}) + : callPrintFunction("%s", {TypeLit})) + return true; + + return dumpRecordValue(RD, E, IndentLit, Depth); + } + + // Dump a record value. E should be a pointer or lvalue referring to an RD. + bool dumpRecordValue(const RecordDecl *RD, Expr *E, Expr *RecordIndent, + unsigned Depth) { + // FIXME: Decide what to do if RD is a union. At least we should probably + // turn off printing `const char*` members with `%s`, because that is very + // likely to crash if that's not the active member. Whatever we decide, we + // should document it. + + // Build an OpaqueValueExpr so we can refer to E more than once without + // triggering re-evaluation. + Expr *RecordArg = makeOpaqueValueExpr(E); + bool RecordArgIsPtr = RecordArg->getType()->isPointerType(); + + if (callPrintFunction(" {\n")) + return true; + + // Dump each base class, regardless of whether they're aggregates. + if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (const auto &Base : CXXRD->bases()) { + QualType BaseType = + RecordArgIsPtr ? S.Context.getPointerType(Base.getType()) + : S.Context.getLValueReferenceType(Base.getType()); + ExprResult BasePtr = S.BuildCStyleCastExpr( + Loc, S.Context.getTrivialTypeSourceInfo(BaseType, Loc), Loc, + RecordArg); + if (BasePtr.isInvalid() || + dumpUnnamedRecord(Base.getType()->getAsRecordDecl(), BasePtr.get(), + Depth + 1)) + return true; + } + } + + Expr *FieldIndentArg = getIndentString(Depth + 1); + + // Dump each field. + for (auto *D : RD->decls()) { + auto *IFD = dyn_cast<IndirectFieldDecl>(D); + auto *FD = IFD ? IFD->getAnonField() : dyn_cast<FieldDecl>(D); + if (!FD || FD->isUnnamedBitfield() || FD->isAnonymousStructOrUnion()) + continue; + + llvm::SmallString<20> Format = llvm::StringRef("%s%s %s "); + llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg, + getTypeString(FD->getType()), + getStringLiteral(FD->getName())}; + + if (FD->isBitField()) { + Format += ": %zu "; + QualType SizeT = S.Context.getSizeType(); + llvm::APInt BitWidth(S.Context.getIntWidth(SizeT), + FD->getBitWidthValue(S.Context)); + Args.push_back(IntegerLiteral::Create(S.Context, BitWidth, SizeT, Loc)); + } + + Format += "="; + + ExprResult Field = + IFD ? S.BuildAnonymousStructUnionMemberReference( + CXXScopeSpec(), Loc, IFD, + DeclAccessPair::make(IFD, AS_public), RecordArg, Loc) + : S.BuildFieldReferenceExpr( + RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD, + DeclAccessPair::make(FD, AS_public), + DeclarationNameInfo(FD->getDeclName(), Loc)); + if (Field.isInvalid()) + return true; + + auto *InnerRD = FD->getType()->getAsRecordDecl(); + auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD); + if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) { + // Recursively print the values of members of aggregate record type. + if (callPrintFunction(Format, Args) || + dumpRecordValue(InnerRD, Field.get(), FieldIndentArg, Depth + 1)) + return true; + } else { + Format += " "; + if (appendFormatSpecifier(FD->getType(), Format)) { + // We know how to print this field. + Args.push_back(Field.get()); + } else { + // We don't know how to print this field. Print out its address + // with a format specifier that a smart tool will be able to + // recognize and treat specially. + Format += "*%p"; + ExprResult FieldAddr = + S.BuildUnaryOp(nullptr, Loc, UO_AddrOf, Field.get()); + if (FieldAddr.isInvalid()) + return true; + Args.push_back(FieldAddr.get()); + } + Format += "\n"; + if (callPrintFunction(Format, Args)) + return true; + } + } + + return RecordIndent ? callPrintFunction("%s}\n", RecordIndent) + : callPrintFunction("}\n"); + } + + Expr *buildWrapper() { + auto *Wrapper = PseudoObjectExpr::Create(S.Context, TheCall, Actions, + PseudoObjectExpr::NoResult); + TheCall->setType(Wrapper->getType()); + TheCall->setValueKind(Wrapper->getValueKind()); + return Wrapper; + } +}; +} // namespace + +static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) { + if (checkArgCountAtLeast(S, TheCall, 2)) + return ExprError(); + + ExprResult PtrArgResult = S.DefaultLvalueConversion(TheCall->getArg(0)); + if (PtrArgResult.isInvalid()) + return ExprError(); + TheCall->setArg(0, PtrArgResult.get()); + + // First argument should be a pointer to a struct. + QualType PtrArgType = PtrArgResult.get()->getType(); + if (!PtrArgType->isPointerType() || + !PtrArgType->getPointeeType()->isRecordType()) { + S.Diag(PtrArgResult.get()->getBeginLoc(), + diag::err_expected_struct_pointer_argument) + << 1 << TheCall->getDirectCallee() << PtrArgType; + return ExprError(); + } + const RecordDecl *RD = PtrArgType->getPointeeType()->getAsRecordDecl(); + + // Second argument is a callable, but we can't fully validate it until we try + // calling it. + QualType FnArgType = TheCall->getArg(1)->getType(); + if (!FnArgType->isFunctionType() && !FnArgType->isFunctionPointerType() && + !FnArgType->isBlockPointerType() && + !(S.getLangOpts().CPlusPlus && FnArgType->isRecordType())) { + auto *BT = FnArgType->getAs<BuiltinType>(); + switch (BT ? BT->getKind() : BuiltinType::Void) { + case BuiltinType::Dependent: + case BuiltinType::Overload: + case BuiltinType::BoundMember: + case BuiltinType::PseudoObject: + case BuiltinType::UnknownAny: + case BuiltinType::BuiltinFn: + // This might be a callable. + break; + + default: + S.Diag(TheCall->getArg(1)->getBeginLoc(), + diag::err_expected_callable_argument) + << 2 << TheCall->getDirectCallee() << FnArgType; + return ExprError(); + } + } + + BuiltinDumpStructGenerator Generator(S, TheCall); + + // Wrap parentheses around the given pointer. This is not necessary for + // correct code generation, but it means that when we pretty-print the call + // arguments in our diagnostics we will produce '(&s)->n' instead of the + // incorrect '&s->n'. + Expr *PtrArg = PtrArgResult.get(); + PtrArg = new (S.Context) + ParenExpr(PtrArg->getBeginLoc(), + S.getLocForEndOfToken(PtrArg->getEndLoc()), PtrArg); + if (Generator.dumpUnnamedRecord(RD, PtrArg, 0)) + return ExprError(); + + return Generator.buildWrapper(); +} + static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { if (checkArgCount(S, BuiltinCall, 2)) return true; @@ -715,7 +1034,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, Optional<unsigned> IndexOptional = TranslateIndex(Index); if (!IndexOptional) return llvm::None; - unsigned NewIndex = IndexOptional.getValue(); + unsigned NewIndex = *IndexOptional; Expr::EvalResult Result; Expr *SizeArg = TheCall->getArg(NewIndex); if (!SizeArg->EvaluateAsInt(Result, getASTContext())) @@ -740,7 +1059,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, Optional<unsigned> IndexOptional = TranslateIndex(Index); if (!IndexOptional) return llvm::None; - unsigned NewIndex = IndexOptional.getValue(); + unsigned NewIndex = *IndexOptional; const Expr *ObjArg = TheCall->getArg(NewIndex); uint64_t Result; @@ -755,7 +1074,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, Optional<unsigned> IndexOptional = TranslateIndex(Index); if (!IndexOptional) return llvm::None; - unsigned NewIndex = IndexOptional.getValue(); + unsigned NewIndex = *IndexOptional; const Expr *ObjArg = TheCall->getArg(NewIndex); uint64_t Result; @@ -820,7 +1139,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (!Format) return; - if (!Format->isAscii() && !Format->isUTF8()) + if (!Format->isOrdinary() && !Format->isUTF8()) return; auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize, @@ -865,7 +1184,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (auto *Format = dyn_cast<StringLiteral>(FormatExpr)) { - if (!Format->isAscii() && !Format->isUTF8()) + if (!Format->isOrdinary() && !Format->isUTF8()) return; StringRef FormatStrRef = Format->getString(); @@ -965,8 +1284,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, } if (!SourceSize || !DestinationSize || - llvm::APSInt::compareValues(SourceSize.getValue(), - DestinationSize.getValue()) <= 0) + llvm::APSInt::compareValues(*SourceSize, *DestinationSize) <= 0) return; StringRef FunctionName = GetFunctionName(); @@ -1042,9 +1360,15 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { } static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { - if (!S.getOpenCLOptions().isSupported("cl_khr_subgroups", S.getLangOpts())) { + // OpenCL device can support extension but not the feature as extension + // requires subgroup independent forward progress, but subgroup independent + // forward progress is optional in OpenCL C 3.0 __opencl_c_subgroups feature. + if (!S.getOpenCLOptions().isSupported("cl_khr_subgroups", S.getLangOpts()) && + !S.getOpenCLOptions().isSupported("__opencl_c_subgroups", + S.getLangOpts())) { S.Diag(Call->getBeginLoc(), diag::err_opencl_requires_extension) - << 1 << Call->getDirectCallee() << "cl_khr_subgroups"; + << 1 << Call->getDirectCallee() + << "cl_khr_subgroups or __opencl_c_subgroups"; return true; } return false; @@ -1549,7 +1873,7 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) { return 2; return llvm::Optional<unsigned>{}; }(); - if (DiagSelect.hasValue()) { + if (DiagSelect) { S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg) << DiagSelect.getValue() << TheCall->getSourceRange(); return ExprError(); @@ -1673,7 +1997,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if ((ICEArguments & (1 << ArgNo)) == 0) continue; llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) + // If we don't have enough arguments, continue so we can issue better + // diagnostic in checkArgCount(...) + if (ArgNo < TheCall->getNumArgs() && + SemaBuiltinConstantArg(TheCall, ArgNo, Result)) return true; ICEArguments &= ~(1 << ArgNo); } @@ -1949,6 +2276,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } break; } + case Builtin::BI__builtin_memset_inline: { + clang::Expr *SizeOp = TheCall->getArg(2); + // We warn about filling to `nullptr` pointers when `size` is greater than + // 0. When `size` is value dependent we cannot evaluate its value so we bail + // out. + if (SizeOp->isValueDependent()) + break; + if (!SizeOp->EvaluateKnownConstInt(Context).isZero()) + CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc()); + break; + } #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ case Builtin::BI##ID: \ @@ -1991,62 +2329,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CorrectDelayedTyposInExpr(TheCallResult.get()); return Res; } - case Builtin::BI__builtin_dump_struct: { - // We first want to ensure we are called with 2 arguments - if (checkArgCount(*this, TheCall, 2)) - return ExprError(); - // Ensure that the first argument is of type 'struct XX *' - const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); - const QualType PtrArgType = PtrArg->getType(); - if (!PtrArgType->isPointerType() || - !PtrArgType->getPointeeType()->isRecordType()) { - Diag(PtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType - << "structure pointer"; - return ExprError(); - } - - // Ensure that the second argument is of type 'FunctionType' - const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts(); - const QualType FnPtrArgType = FnPtrArg->getType(); - if (!FnPtrArgType->isPointerType()) { - Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 << 2 - << FnPtrArgType << "'int (*)(const char *, ...)'"; - return ExprError(); - } - - const auto *FuncType = - FnPtrArgType->getPointeeType()->getAs<FunctionType>(); - - if (!FuncType) { - Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 << 2 - << FnPtrArgType << "'int (*)(const char *, ...)'"; - return ExprError(); - } - - if (const auto *FT = dyn_cast<FunctionProtoType>(FuncType)) { - if (!FT->getNumParams()) { - Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 - << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; - return ExprError(); - } - QualType PT = FT->getParamType(0); - if (!FT->isVariadic() || FT->getReturnType() != Context.IntTy || - !PT->isPointerType() || !PT->getPointeeType()->isCharType() || - !PT->getPointeeType().isConstQualified()) { - Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 - << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; - return ExprError(); - } - } - - TheCall->setType(Context.IntTy); - break; - } + case Builtin::BI__builtin_dump_struct: + return SemaBuiltinDumpStruct(*this, TheCall); case Builtin::BI__builtin_expect_with_probability: { // We first want to ensure we are called with 3 arguments if (checkArgCount(*this, TheCall, 3)) @@ -2108,6 +2392,32 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.VoidPtrTy); break; + case Builtin::BIaddressof: + case Builtin::BI__addressof: + case Builtin::BIforward: + case Builtin::BImove: + case Builtin::BImove_if_noexcept: + case Builtin::BIas_const: { + // These are all expected to be of the form + // T &/&&/* f(U &/&&) + // where T and U only differ in qualification. + if (checkArgCount(*this, TheCall, 1)) + return ExprError(); + QualType Param = FDecl->getParamDecl(0)->getType(); + QualType Result = FDecl->getReturnType(); + bool ReturnsPointer = BuiltinID == Builtin::BIaddressof || + BuiltinID == Builtin::BI__addressof; + if (!(Param->isReferenceType() && + (ReturnsPointer ? Result->isPointerType() + : Result->isReferenceType()) && + Context.hasSameUnqualifiedType(Param->getPointeeType(), + Result->getPointeeType()))) { + Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported) + << FDecl; + return ExprError(); + } + break; + } // OpenCL v2.0, s6.13.16 - Pipe functions case Builtin::BIread_pipe: case Builtin::BIwrite_pipe: @@ -2238,6 +2548,28 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } + // These builtins restrict the element type to integer + // types only. + case Builtin::BI__builtin_elementwise_add_sat: + case Builtin::BI__builtin_elementwise_sub_sat: { + if (SemaBuiltinElementwiseMath(TheCall)) + return ExprError(); + + const Expr *Arg = TheCall->getArg(0); + QualType ArgTy = Arg->getType(); + QualType EltTy = ArgTy; + + if (auto *VecTy = EltTy->getAs<VectorType>()) + EltTy = VecTy->getElementType(); + + if (!EltTy->isIntegerType()) { + Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /* integer ty */ 6 << ArgTy; + return ExprError(); + } + break; + } + case Builtin::BI__builtin_elementwise_min: case Builtin::BI__builtin_elementwise_max: if (SemaBuiltinElementwiseMath(TheCall)) @@ -2261,6 +2593,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } // These builtins support vectors of integers only. + // TODO: ADD/MUL should support floating-point types. + case Builtin::BI__builtin_reduce_add: + case Builtin::BI__builtin_reduce_mul: case Builtin::BI__builtin_reduce_xor: case Builtin::BI__builtin_reduce_or: case Builtin::BI__builtin_reduce_and: { @@ -2878,6 +3213,9 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, if (BuiltinID == AArch64::BI__getReg) return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + if (BuiltinID == AArch64::BI__break) + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xffff); + if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) return true; @@ -2911,23 +3249,12 @@ static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { isa<ArraySubscriptExpr>(Arg->IgnoreParens())); } -static bool isEltOfVectorTy(ASTContext &Context, CallExpr *Call, Sema &S, - QualType VectorTy, QualType EltTy) { - QualType VectorEltTy = VectorTy->castAs<VectorType>()->getElementType(); - if (!Context.hasSameType(VectorEltTy, EltTy)) { - S.Diag(Call->getBeginLoc(), diag::err_typecheck_call_different_arg_types) - << Call->getSourceRange() << VectorEltTy << EltTy; - return false; - } - return true; -} - static bool isValidBPFPreserveTypeInfoArg(Expr *Arg) { QualType ArgType = Arg->getType(); if (ArgType->getAsPlaceholderType()) return false; - // for TYPE_EXISTENCE/TYPE_SIZEOF reloc type + // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type // format: // 1. __builtin_preserve_type_info(*(<type> *)0, flag); // 2. <type> var; @@ -3576,6 +3903,8 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { case PPC::BI__builtin_divde: case PPC::BI__builtin_divdeu: case PPC::BI__builtin_bpermd: + case PPC::BI__builtin_pdepd: + case PPC::BI__builtin_pextd: case PPC::BI__builtin_ppc_ldarx: case PPC::BI__builtin_ppc_stdcx: case PPC::BI__builtin_ppc_tdw: @@ -3735,16 +4064,12 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_pack_vector_int128: return SemaFeatureCheck(*this, TheCall, "vsx", diag::err_ppc_builtin_only_on_arch, "7"); + case PPC::BI__builtin_pdepd: + case PPC::BI__builtin_pextd: + return SemaFeatureCheck(*this, TheCall, "isa-v31-instructions", + diag::err_ppc_builtin_only_on_arch, "10"); case PPC::BI__builtin_altivec_vgnb: return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7); - case PPC::BI__builtin_altivec_vec_replace_elt: - case PPC::BI__builtin_altivec_vec_replace_unaligned: { - QualType VecTy = TheCall->getArg(0)->getType(); - QualType EltTy = TheCall->getArg(1)->getType(); - unsigned Width = Context.getIntWidth(EltTy); - return SemaBuiltinConstantArgRange(TheCall, 2, 0, Width == 32 ? 12 : 8) || - !isEltOfVectorTy(Context, TheCall, *this, VecTy, EltTy); - } case PPC::BI__builtin_vsx_xxeval: return SemaBuiltinConstantArgRange(TheCall, 3, 0, 255); case PPC::BI__builtin_altivec_vsldbi: @@ -3854,6 +4179,33 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, diag::err_ppc_builtin_requires_vsx) || SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); } + case PPC::BI__builtin_ppc_maxfe: + case PPC::BI__builtin_ppc_minfe: + case PPC::BI__builtin_ppc_maxfl: + case PPC::BI__builtin_ppc_minfl: + case PPC::BI__builtin_ppc_maxfs: + case PPC::BI__builtin_ppc_minfs: { + if (Context.getTargetInfo().getTriple().isOSAIX() && + (BuiltinID == PPC::BI__builtin_ppc_maxfe || + BuiltinID == PPC::BI__builtin_ppc_minfe)) + return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type) + << "builtin" << true << 128 << QualType(Context.LongDoubleTy) + << false << Context.getTargetInfo().getTriple().str(); + // Argument type should be exact. + QualType ArgType = QualType(Context.LongDoubleTy); + if (BuiltinID == PPC::BI__builtin_ppc_maxfl || + BuiltinID == PPC::BI__builtin_ppc_minfl) + ArgType = QualType(Context.DoubleTy); + else if (BuiltinID == PPC::BI__builtin_ppc_maxfs || + BuiltinID == PPC::BI__builtin_ppc_minfs) + ArgType = QualType(Context.FloatTy); + for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I) + if (TheCall->getArg(I)->getType() != ArgType) + return Diag(TheCall->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; + return false; + } case PPC::BI__builtin_ppc_load8r: case PPC::BI__builtin_ppc_store8r: return SemaFeatureCheck(*this, TheCall, "isa-v206-instructions", @@ -3964,6 +4316,27 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) { << Arg->getSourceRange(); } +static bool isRISCV32Builtin(unsigned BuiltinID) { + // These builtins only work on riscv32 targets. + switch (BuiltinID) { + case RISCV::BI__builtin_riscv_zip_32: + case RISCV::BI__builtin_riscv_unzip_32: + case RISCV::BI__builtin_riscv_aes32dsi_32: + case RISCV::BI__builtin_riscv_aes32dsmi_32: + case RISCV::BI__builtin_riscv_aes32esi_32: + case RISCV::BI__builtin_riscv_aes32esmi_32: + case RISCV::BI__builtin_riscv_sha512sig0h_32: + case RISCV::BI__builtin_riscv_sha512sig0l_32: + case RISCV::BI__builtin_riscv_sha512sig1h_32: + case RISCV::BI__builtin_riscv_sha512sig1l_32: + case RISCV::BI__builtin_riscv_sha512sum0r_32: + case RISCV::BI__builtin_riscv_sha512sum1r_32: + return true; + } + + return false; +} + bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { @@ -3974,6 +4347,12 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); Features.split(ReqFeatures, ','); + // Check for 32-bit only builtins on a 64-bit target. + const llvm::Triple &TT = TI.getTriple(); + if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID)) + return Diag(TheCall->getCallee()->getBeginLoc(), + diag::err_32_bit_builtin_64_bit_tgt); + // Check if each required feature is included for (StringRef F : ReqFeatures) { SmallVector<StringRef> ReqOpFeatures; @@ -4021,6 +4400,41 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vsetvlimax: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || CheckRISCVLMUL(TheCall, 1); + case RISCVVector::BI__builtin_rvv_vget_v: { + ASTContext::BuiltinVectorTypeInfo ResVecInfo = + Context.getBuiltinVectorTypeInfo(cast<BuiltinType>( + TheCall->getType().getCanonicalType().getTypePtr())); + ASTContext::BuiltinVectorTypeInfo VecInfo = + Context.getBuiltinVectorTypeInfo(cast<BuiltinType>( + TheCall->getArg(0)->getType().getCanonicalType().getTypePtr())); + unsigned MaxIndex = + (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / + (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + } + case RISCVVector::BI__builtin_rvv_vset_v: { + ASTContext::BuiltinVectorTypeInfo ResVecInfo = + Context.getBuiltinVectorTypeInfo(cast<BuiltinType>( + TheCall->getType().getCanonicalType().getTypePtr())); + ASTContext::BuiltinVectorTypeInfo VecInfo = + Context.getBuiltinVectorTypeInfo(cast<BuiltinType>( + TheCall->getArg(2)->getType().getCanonicalType().getTypePtr())); + unsigned MaxIndex = + (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / + (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + } + // Check if byteselect is in [0, 3] + case RISCV::BI__builtin_riscv_aes32dsi_32: + case RISCV::BI__builtin_riscv_aes32dsmi_32: + case RISCV::BI__builtin_riscv_aes32esi_32: + case RISCV::BI__builtin_riscv_aes32esmi_32: + case RISCV::BI__builtin_riscv_sm4ks: + case RISCV::BI__builtin_riscv_sm4ed: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + // Check if rnum is in [0, 10] + case RISCV::BI__builtin_riscv_aes64ks1i_64: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 10); } return false; @@ -5409,7 +5823,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, if (!FnInfo) return false; - CheckTCBEnforcement(TheCall, FDecl); + // Enforce TCB except for builtin calls, which are always allowed. + if (FDecl->getBuiltinID() == 0) + CheckTCBEnforcement(TheCall->getExprLoc(), FDecl); CheckAbsoluteValueFunction(TheCall, FDecl); CheckMaxUnsignedZero(TheCall, FDecl); @@ -5449,6 +5865,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), CallType); + CheckTCBEnforcement(lbrac, Method); + return false; } @@ -6053,7 +6471,7 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { InitializedEntity Entity = InitializedEntity::InitializeParameter(S.Context, Param); - ExprResult Arg = E->getArg(0); + ExprResult Arg = E->getArg(ArgIndex); Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; @@ -6520,7 +6938,7 @@ bool Sema::CheckObjCString(Expr *Arg) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Literal = dyn_cast<StringLiteral>(Arg); - if (!Literal || !Literal->isAscii()) { + if (!Literal || !Literal->isOrdinary()) { Diag(Arg->getBeginLoc(), diag::err_cfstring_literal_not_string_constant) << Arg->getSourceRange(); return true; @@ -6555,7 +6973,7 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { } } - if (!Literal || (!Literal->isAscii() && !Literal->isUTF8())) { + if (!Literal || (!Literal->isOrdinary() && !Literal->isUTF8())) { return ExprError( Diag(Arg->getBeginLoc(), diag::err_os_log_format_not_string_constant) << Arg->getSourceRange()); @@ -7972,7 +8390,7 @@ class FormatStringLiteral { QualType getType() const { return FExpr->getType(); } - bool isAscii() const { return FExpr->isAscii(); } + bool isAscii() const { return FExpr->isOrdinary(); } bool isWide() const { return FExpr->isWide(); } bool isUTF8() const { return FExpr->isUTF8(); } bool isUTF16() const { return FExpr->isUTF16(); } @@ -10760,7 +11178,10 @@ static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) { Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts(); auto isLiteralZero = [](const Expr *E) { - return isa<IntegerLiteral>(E) && cast<IntegerLiteral>(E)->getValue() == 0; + return (isa<IntegerLiteral>(E) && + cast<IntegerLiteral>(E)->getValue() == 0) || + (isa<CharacterLiteral>(E) && + cast<CharacterLiteral>(E)->getValue() == 0); }; // If we're memsetting or bzeroing 0 bytes, then this is likely an error. @@ -11282,7 +11703,7 @@ void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName, /// Alerts the user that they are attempting to free a non-malloc'd object. void Sema::CheckFreeArguments(const CallExpr *E) { const std::string CalleeName = - dyn_cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString(); + cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString(); { // Prefer something that doesn't involve a cast to make things simpler. const Expr *Arg = E->getArg(0)->IgnoreParenCasts(); @@ -11353,12 +11774,40 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, CheckPPCMMAType(RetValExp->getType(), ReturnLoc); } -//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// +/// Check for comparisons of floating-point values using == and !=. Issue a +/// warning if the comparison is not likely to do what the programmer intended. +void Sema::CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS, + BinaryOperatorKind Opcode) { + // Match and capture subexpressions such as "(float) X == 0.1". + FloatingLiteral *FPLiteral; + CastExpr *FPCast; + auto getCastAndLiteral = [&FPLiteral, &FPCast](Expr *L, Expr *R) { + FPLiteral = dyn_cast<FloatingLiteral>(L->IgnoreParens()); + FPCast = dyn_cast<CastExpr>(R->IgnoreParens()); + return FPLiteral && FPCast; + }; + + if (getCastAndLiteral(LHS, RHS) || getCastAndLiteral(RHS, LHS)) { + auto *SourceTy = FPCast->getSubExpr()->getType()->getAs<BuiltinType>(); + auto *TargetTy = FPLiteral->getType()->getAs<BuiltinType>(); + if (SourceTy && TargetTy && SourceTy->isFloatingPoint() && + TargetTy->isFloatingPoint()) { + bool Lossy; + llvm::APFloat TargetC = FPLiteral->getValue(); + TargetC.convert(Context.getFloatTypeSemantics(QualType(SourceTy, 0)), + llvm::APFloat::rmNearestTiesToEven, &Lossy); + if (Lossy) { + // If the literal cannot be represented in the source type, then a + // check for == is always false and check for != is always true. + Diag(Loc, diag::warn_float_compare_literal) + << (Opcode == BO_EQ) << QualType(SourceTy, 0) + << LHS->getSourceRange() << RHS->getSourceRange(); + return; + } + } + } -/// Check for comparisons of floating point operands using != and ==. -/// Issue a warning if these are no self-comparisons, as they are not likely -/// to do what the programmer intended. -void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) { + // Match a more general floating-point equality comparison (-Wfloat-equal). Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts(); Expr* RightExprSansParen = RHS->IgnoreParenImpCasts(); @@ -13105,6 +13554,29 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source); const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target); + // Strip SVE vector types + if (SourceBT && SourceBT->isVLSTBuiltinType()) { + // Need the original target type for vector type checks + const Type *OriginalTarget = S.Context.getCanonicalType(T).getTypePtr(); + // Handle conversion from scalable to fixed when msve-vector-bits is + // specified + if (S.Context.areCompatibleSveTypes(QualType(OriginalTarget, 0), + QualType(Source, 0)) || + S.Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0), + QualType(Source, 0))) + return; + + // If the vector cast is cast between two vectors of the same size, it is + // a bitcast, not a conversion. + if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) + return; + + Source = SourceBT->getSveEltType(S.Context).getTypePtr(); + } + + if (TargetBT && TargetBT->isVLSTBuiltinType()) + Target = TargetBT->getSveEltType(S.Context).getTypePtr(); + // If the source is floating point... if (SourceBT && SourceBT->isFloatingPoint()) { // ...and the target is floating point... @@ -13390,9 +13862,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Fall through for non-constants to give a sign conversion warning. } - if ((TargetRange.NonNegative && !LikelySourceRange.NonNegative) || - (!TargetRange.NonNegative && LikelySourceRange.NonNegative && - LikelySourceRange.Width == TargetRange.Width)) { + if ((!isa<EnumType>(Target) || !isa<EnumType>(Source)) && + ((TargetRange.NonNegative && !LikelySourceRange.NonNegative) || + (!TargetRange.NonNegative && LikelySourceRange.NonNegative && + LikelySourceRange.Width == TargetRange.Width))) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -13623,6 +14096,13 @@ static void AnalyzeImplicitConversions( if (!ChildExpr) continue; + if (auto *CSE = dyn_cast<CoroutineSuspendExpr>(E)) + if (ChildExpr == CSE->getOperand()) + // Do not recurse over a CoroutineSuspendExpr's operand. + // The operand is also a subexpression of getCommonExpr(), and + // recursing into it directly would produce duplicate diagnostics. + continue; + if (IsLogicalAndOperator && isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts())) // Ignore checking string literals that are in logical and operators. @@ -15324,6 +15804,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, ND = ME->getMemberDecl(); if (IsUnboundedArray) { + if (EffectiveType->isFunctionType()) + return; if (index.isUnsigned() || !index.isNegative()) { const auto &ASTC = getASTContext(); unsigned AddrBits = @@ -16191,7 +16673,7 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S, Body = FS->getBody(); DiagID = diag::warn_empty_for_body; } else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) { - StmtLoc = WS->getCond()->getSourceRange().getEnd(); + StmtLoc = WS->getRParenLoc(); Body = WS->getBody(); DiagID = diag::warn_empty_while_body; } else @@ -17243,33 +17725,28 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, /// CheckTCBEnforcement - Enforces that every function in a named TCB only /// directly calls other functions in the same TCB as marked by the enforce_tcb /// and enforce_tcb_leaf attributes. -void Sema::CheckTCBEnforcement(const CallExpr *TheCall, - const FunctionDecl *Callee) { - const FunctionDecl *Caller = getCurFunctionDecl(); +void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc, + const NamedDecl *Callee) { + const NamedDecl *Caller = getCurFunctionOrMethodDecl(); - // Calls to builtins are not enforced. - if (!Caller || !Caller->hasAttr<EnforceTCBAttr>() || - Callee->getBuiltinID() != 0) + if (!Caller || !Caller->hasAttr<EnforceTCBAttr>()) return; // Search through the enforce_tcb and enforce_tcb_leaf attributes to find // all TCBs the callee is a part of. llvm::StringSet<> CalleeTCBs; - for_each(Callee->specific_attrs<EnforceTCBAttr>(), - [&](const auto *A) { CalleeTCBs.insert(A->getTCBName()); }); - for_each(Callee->specific_attrs<EnforceTCBLeafAttr>(), - [&](const auto *A) { CalleeTCBs.insert(A->getTCBName()); }); + for (const auto *A : Callee->specific_attrs<EnforceTCBAttr>()) + CalleeTCBs.insert(A->getTCBName()); + for (const auto *A : Callee->specific_attrs<EnforceTCBLeafAttr>()) + CalleeTCBs.insert(A->getTCBName()); // Go through the TCBs the caller is a part of and emit warnings if Caller // is in a TCB that the Callee is not. - for_each( - Caller->specific_attrs<EnforceTCBAttr>(), - [&](const auto *A) { - StringRef CallerTCB = A->getTCBName(); - if (CalleeTCBs.count(CallerTCB) == 0) { - this->Diag(TheCall->getExprLoc(), - diag::warn_tcb_enforcement_violation) << Callee - << CallerTCB; - } - }); + for (const auto *A : Caller->specific_attrs<EnforceTCBAttr>()) { + StringRef CallerTCB = A->getTCBName(); + if (CalleeTCBs.count(CallerTCB) == 0) { + this->Diag(CallExprLoc, diag::warn_tcb_enforcement_violation) + << Callee << CallerTCB; + } + } } |
