SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo) { assert(constantInfo == getConstantInfo(constant)); // Builtins must be fully applied at the point of reference. if (constant.hasDecl() && isa<BuiltinUnit>(constant.getDecl()->getDeclContext())) { SGM.diagnose(loc.getSourceLoc(), diag::not_implemented, "delayed application of builtin"); return SILUndef::get(constantInfo.getSILType(), SGM.M); } // If the constant is a thunk we haven't emitted yet, emit it. if (!SGM.hasFunction(constant)) { if (constant.isCurried) { SGM.emitCurryThunk(constant); } else if (constant.isForeignToNativeThunk()) { SGM.emitForeignToNativeThunk(constant); } else if (constant.isNativeToForeignThunk()) { SGM.emitNativeToForeignThunk(constant); } else if (constant.kind == SILDeclRef::Kind::EnumElement) { SGM.emitEnumConstructor(cast<EnumElementDecl>(constant.getDecl())); } } auto f = SGM.getFunction(constant, NotForDefinition); assert(f->getLoweredFunctionType() == constantInfo.SILFnType); return B.createFunctionRef(loc, f); }
/// Given that this is an 'Unknown' value, emit diagnostic notes providing /// context about what the problem is. void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { auto badInst = dyn_cast<SILInstruction>(getUnknownNode()); if (!badInst) return; bool emittedFirstNote = emitNoteDiagnostic(badInst, getUnknownReason(), fallbackLoc); auto sourceLoc = fallbackLoc.getSourceLoc(); auto &module = badInst->getModule(); if (sourceLoc.isInvalid()) { diagnose(module.getASTContext(), sourceLoc, diag::constexpr_not_evaluable); return; } for (auto &sourceLoc : llvm::reverse(getUnknownCallStack())) { // Skip unknown sources. if (!sourceLoc.isValid()) continue; auto diag = emittedFirstNote ? diag::constexpr_called_from : diag::constexpr_not_evaluable; diagnose(module.getASTContext(), sourceLoc, diag); emittedFirstNote = true; } }
static void diagnoseReturn(const SILInstruction *I, ASTContext &Context) { auto *TI = dyn_cast<TermInst>(I); if (!TI || !(isa<BranchInst>(TI) || isa<ReturnInst>(TI))) return; const SILBasicBlock *BB = TI->getParent(); const SILFunction *F = BB->getParent(); // Warn if we reach a return inside a noreturn function. if (F->getLoweredFunctionType()->isNoReturn()) { SILLocation L = TI->getLoc(); if (L.is<ReturnLocation>()) diagnose(Context, L.getSourceLoc(), diag::return_from_noreturn); if (L.is<ImplicitReturnLocation>()) diagnose(Context, L.getSourceLoc(), diag::return_from_noreturn); } }
SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo) { assert(constantInfo == getConstantInfo(constant)); // Builtins must be fully applied at the point of reference. if (constant.hasDecl() && isa<BuiltinUnit>(constant.getDecl()->getDeclContext())) { SGM.diagnose(loc.getSourceLoc(), diag::not_implemented, "delayed application of builtin"); return SILUndef::get(constantInfo.getSILType(), SGM.M); } // If the constant is a thunk we haven't emitted yet, emit it. if (!SGM.hasFunction(constant)) { if (constant.isCurried) { auto vd = constant.getDecl(); // Reference the next uncurrying level of the function. SILDeclRef next = SILDeclRef(vd, constant.kind, SILDeclRef::ConstructAtBestResilienceExpansion, constant.uncurryLevel + 1); // If the function is fully uncurried and natively foreign, reference its // foreign entry point. if (!next.isCurried) { if (requiresForeignToNativeThunk(vd)) next = next.asForeign(); } // Preserve whether the curry thunks lead to a direct reference to the // method implementation. next = next.asDirectReference(constant.isDirectReference); SGM.emitCurryThunk(vd, constant, next); } // Otherwise, if this is a calling convention thunk we haven't emitted yet, // emit it. else if (constant.isForeignToNativeThunk()) { SGM.emitForeignToNativeThunk(constant); } else if (constant.isNativeToForeignThunk()) { SGM.emitNativeToForeignThunk(constant); } else if (constant.kind == SILDeclRef::Kind::EnumElement) { SGM.emitEnumConstructor(cast<EnumElementDecl>(constant.getDecl())); } } auto f = SGM.getFunction(constant, NotForDefinition); assert(f->getLoweredFunctionType() == constantInfo.SILFnType); return B.createFunctionRef(loc, f); }
void swift::printSILLocationDescription(llvm::raw_ostream &out, SILLocation loc, ASTContext &Context) { if (loc.isNull()) { out << "<<invalid location>>"; } else if (loc.isSILFile()) { printSourceLocDescription(out, loc.getSourceLoc(), Context); } else if (auto decl = loc.getAsASTNode<Decl>()) { printDeclDescription(out, decl, Context); } else if (auto expr = loc.getAsASTNode<Expr>()) { printExprDescription(out, expr, Context); } else if (auto stmt = loc.getAsASTNode<Stmt>()) { printStmtDescription(out, stmt, Context); } else if (auto pattern = loc.castToASTNode<Pattern>()) { printPatternDescription(out, pattern, Context); } }
static void emitSourceLocationArgs(SILGenFunction &gen, SILLocation loc, ManagedValue (&args)[4]) { auto &ctx = gen.getASTContext(); auto sourceLoc = loc.getSourceLoc(); StringRef filename = ""; unsigned line = 0; if (sourceLoc.isValid()) { unsigned bufferID = ctx.SourceMgr.findBufferContainingLoc(sourceLoc); filename = ctx.SourceMgr.getIdentifierForBuffer(bufferID); line = ctx.SourceMgr.getLineAndColumn(sourceLoc).first; } bool isASCII = true; for (unsigned char c : filename) { if (c > 127) { isASCII = false; break; } } auto wordTy = SILType::getBuiltinWordType(ctx); auto i1Ty = SILType::getBuiltinIntegerType(1, ctx); // File SILValue literal = gen.B.createStringLiteral(loc, filename, StringLiteralInst::Encoding::UTF8); args[0] = ManagedValue::forUnmanaged(literal); // File length literal = gen.B.createIntegerLiteral(loc, wordTy, filename.size()); args[1] = ManagedValue::forUnmanaged(literal); // File is ascii literal = gen.B.createIntegerLiteral(loc, i1Ty, isASCII); args[2] = ManagedValue::forUnmanaged(literal); // Line literal = gen.B.createIntegerLiteral(loc, wordTy, line); args[3] = ManagedValue::forUnmanaged(literal); }
/// \brief Issue an "unreachable code" diagnostic if the blocks contains or /// leads to another block that contains user code. /// /// Note, we rely on SILLocation information to determine if SILInstructions /// correspond to user code. static bool diagnoseUnreachableBlock(const SILBasicBlock &B, SILModule &M, const SILBasicBlockSet &Reachable, UnreachableUserCodeReportingState *State, const SILBasicBlock *TopLevelB, llvm::SmallPtrSetImpl<const SILBasicBlock*> &Visited){ if (Visited.count(&B)) return false; Visited.insert(&B); assert(State); for (auto I = B.begin(), E = B.end(); I != E; ++I) { SILLocation Loc = I->getLoc(); // If we've reached an implicit return, we have not found any user code and // can stop searching for it. if (Loc.is<ImplicitReturnLocation>() || Loc.isAutoGenerated()) return false; // Check if the instruction corresponds to user-written code, also make // sure we don't report an error twice for the same instruction. if (isUserCode(&*I) && !State->BlocksWithErrors.count(&B)) { // Emit the diagnostic. auto BrInfoIter = State->MetaMap.find(TopLevelB); assert(BrInfoIter != State->MetaMap.end()); auto BrInfo = BrInfoIter->second; switch (BrInfo.Kind) { case (UnreachableKind::FoldedBranch): // Emit the diagnostic on the unreachable block and emit the // note on the branch responsible for the unreachable code. diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::unreachable_code); diagnose(M.getASTContext(), BrInfo.Loc.getSourceLoc(), diag::unreachable_code_branch, BrInfo.CondIsAlwaysTrue); break; case (UnreachableKind::FoldedSwitchEnum): { // If we are warning about a switch condition being a constant, the main // emphasis should be on the condition (to ensure we have a single // message per switch). const SwitchStmt *SS = BrInfo.Loc.getAsASTNode<SwitchStmt>(); if (!SS) break; assert(SS); const Expr *SE = SS->getSubjectExpr(); diagnose(M.getASTContext(), SE->getLoc(), diag::switch_on_a_constant); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::unreachable_code_note); break; } case (UnreachableKind::NoreturnCall): { // Specialcase when we are warning about unreachable code after a call // to a noreturn function. if (!BrInfo.Loc.isASTNode<ExplicitCastExpr>()) { assert(BrInfo.Loc.isASTNode<ApplyExpr>()); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::unreachable_code); diagnose(M.getASTContext(), BrInfo.Loc.getSourceLoc(), diag::call_to_noreturn_note); } break; } } // Record that we've reported this unreachable block to avoid duplicates // in the future. State->BlocksWithErrors.insert(&B); return true; } } // This block could be empty if it's terminator has been folded. if (B.empty()) return false; // If we have not found user code in this block, inspect it's successors. // Check if at least one of the successors contains user code. for (auto I = B.succ_begin(), E = B.succ_end(); I != E; ++I) { SILBasicBlock *SB = *I; bool HasReachablePred = false; for (auto PI = SB->pred_begin(), PE = SB->pred_end(); PI != PE; ++PI) { if (Reachable.count(*PI)) HasReachablePred = true; } // If all of the predecessors of this successor are unreachable, check if // it contains user code. if (!HasReachablePred && diagnoseUnreachableBlock(*SB, M, Reachable, State, TopLevelB, Visited)) return true; } return false; }
ManagedValue SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc, ManagedValue optional) { // Generate code to the optional is present, and if not, abort with a message // (provided by the stdlib). SILBasicBlock *contBB = createBasicBlock(); SILBasicBlock *failBB = createBasicBlock(); bool hadCleanup = optional.hasCleanup(); bool hadLValue = optional.isLValue(); auto noneDecl = getASTContext().getOptionalNoneDecl(); auto someDecl = getASTContext().getOptionalSomeDecl(); if (optional.getType().isAddress()) { // We forward in the creation routine for // unchecked_take_enum_data_addr. switch_enum_addr is a +0 operation. B.createSwitchEnumAddr(loc, optional.getValue(), /*defaultDest*/ nullptr, {{someDecl, contBB}, {noneDecl, failBB}}); } else { B.createSwitchEnum(loc, optional.forward(*this), /*defaultDest*/ nullptr, {{someDecl, contBB}, {noneDecl, failBB}}); } B.emitBlock(failBB); // Call the standard library implementation of _diagnoseUnexpectedNilOptional. if (auto diagnoseFailure = getASTContext().getDiagnoseUnexpectedNilOptional(nullptr)) { auto args = emitSourceLocationArgs(loc.getSourceLoc(), loc); emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, SubstitutionMap(), { args.filenameStartPointer, args.filenameLength, args.filenameIsAscii, args.line }, SGFContext()); } B.createUnreachable(loc); B.clearInsertionPoint(); B.emitBlock(contBB); ManagedValue result; SILType payloadType = optional.getType().getAnyOptionalObjectType(); if (payloadType.isObject()) { result = B.createOwnedPHIArgument(payloadType); } else { result = B.createUncheckedTakeEnumDataAddr(loc, optional, someDecl, payloadType); } if (hadCleanup) { return result; } if (hadLValue) { return ManagedValue::forLValue(result.forward(*this)); } return ManagedValue::forUnmanaged(result.forward(*this)); }
static SILInstruction *constantFoldBuiltin(BuiltinInst *BI, Optional<bool> &ResultsInError) { const IntrinsicInfo &Intrinsic = BI->getIntrinsicInfo(); SILModule &M = BI->getModule(); // If it's an llvm intrinsic, fold the intrinsic. if (Intrinsic.ID != llvm::Intrinsic::not_intrinsic) return constantFoldIntrinsic(BI, Intrinsic.ID, ResultsInError); // Otherwise, it should be one of the builtin functions. OperandValueArrayRef Args = BI->getArguments(); const BuiltinInfo &Builtin = BI->getBuiltinInfo(); switch (Builtin.ID) { default: break; // Check and fold binary arithmetic with overflow. #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinaryWithOverflow(BI, Builtin.ID, ResultsInError); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinary(BI, Builtin.ID, ResultsInError); // Fold comparison predicates. #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldCompare(BI, Builtin.ID); case BuiltinValueKind::Trunc: case BuiltinValueKind::ZExt: case BuiltinValueKind::SExt: case BuiltinValueKind::TruncOrBitCast: case BuiltinValueKind::ZExtOrBitCast: case BuiltinValueKind::SExtOrBitCast: { // We can fold if the value being cast is a constant. auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt CastResV = constantFoldCast(V->getValue(), Builtin); // Add the literal instruction to represent the result of the cast. SILBuilderWithScope B(BI); return B.createIntegerLiteral(BI->getLoc(), BI->getType(), CastResV); } // Process special builtins that are designed to check for overflows in // integer conversions. case BuiltinValueKind::SToSCheckedTrunc: case BuiltinValueKind::UToUCheckedTrunc: case BuiltinValueKind::SToUCheckedTrunc: case BuiltinValueKind::UToSCheckedTrunc: case BuiltinValueKind::SUCheckedConversion: case BuiltinValueKind::USCheckedConversion: { return constantFoldAndCheckIntegerConversions(BI, Builtin, ResultsInError); } case BuiltinValueKind::IntToFPWithOverflow: { // Get the value. It should be a constant in most cases. // Note, this will not always be a constant, for example, when analyzing // _convertFromBuiltinIntegerLiteral function itself. auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt SrcVal = V->getValue(); Type DestTy = Builtin.Types[1]; APFloat TruncVal( DestTy->castTo<BuiltinFloatType>()->getAPFloatSemantics()); APFloat::opStatus ConversionStatus = TruncVal.convertFromAPInt( SrcVal, /*isSigned=*/true, APFloat::rmNearestTiesToEven); SILLocation Loc = BI->getLoc(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); // Check for overflow. if (ConversionStatus & APFloat::opOverflow) { // If we overflow and are not asked for diagnostics, just return nullptr. if (!ResultsInError.hasValue()) return nullptr; SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, true /*isSigned*/); // Otherwise emit our diagnostics and then return nullptr. diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow, CE ? CE->getType() : DestTy, SrcAsString); ResultsInError = Optional<bool>(true); return nullptr; } // The call to the builtin should be replaced with the constant value. SILBuilderWithScope B(BI); return B.createFloatLiteral(Loc, BI->getType(), TruncVal); } case BuiltinValueKind::FPTrunc: { // Get the value. It should be a constant in most cases. auto *V = dyn_cast<FloatLiteralInst>(Args[0]); if (!V) return nullptr; APFloat TruncVal = V->getValue(); Type DestTy = Builtin.Types[1]; bool losesInfo; APFloat::opStatus ConversionStatus = TruncVal.convert( DestTy->castTo<BuiltinFloatType>()->getAPFloatSemantics(), APFloat::rmNearestTiesToEven, &losesInfo); SILLocation Loc = BI->getLoc(); // Check if conversion was successful. if (ConversionStatus != APFloat::opStatus::opOK && ConversionStatus != APFloat::opStatus::opInexact) { return nullptr; } // The call to the builtin should be replaced with the constant value. SILBuilderWithScope B(BI); return B.createFloatLiteral(Loc, BI->getType(), TruncVal); } case BuiltinValueKind::AssumeNonNegative: { auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt VInt = V->getValue(); if (VInt.isNegative() && ResultsInError.hasValue()) { diagnose(M.getASTContext(), BI->getLoc().getSourceLoc(), diag::wrong_non_negative_assumption, VInt.toString(/*Radix*/ 10, /*Signed*/ true)); ResultsInError = Optional<bool>(true); } return V; } } return nullptr; }
/// \brief Fold arithmetic intrinsics with overflow. static SILInstruction * constantFoldBinaryWithOverflow(BuiltinInst *BI, llvm::Intrinsic::ID ID, bool ReportOverflow, Optional<bool> &ResultsInError) { OperandValueArrayRef Args = BI->getArguments(); assert(Args.size() >= 2); auto *Op1 = dyn_cast<IntegerLiteralInst>(Args[0]); auto *Op2 = dyn_cast<IntegerLiteralInst>(Args[1]); // If either Op1 or Op2 is not a literal, we cannot do anything. if (!Op1 || !Op2) return nullptr; // Calculate the result. APInt LHSInt = Op1->getValue(); APInt RHSInt = Op2->getValue(); bool Overflow; APInt Res = constantFoldBinaryWithOverflow(LHSInt, RHSInt, Overflow, ID); // If we can statically determine that the operation overflows, // warn about it if warnings are not disabled by ResultsInError being null. if (ResultsInError.hasValue() && Overflow && ReportOverflow) { // Try to infer the type of the constant expression that the user operates // on. If the intrinsic was lowered from a call to a function that takes // two arguments of the same type, use the type of the LHS argument. // This would detect '+'/'+=' and such. Type OpType; SILLocation Loc = BI->getLoc(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); SourceRange LHSRange, RHSRange; if (CE) { const auto *Args = dyn_cast_or_null<TupleExpr>(CE->getArg()); if (Args && Args->getNumElements() == 2) { // Look through inout types in order to handle += well. CanType LHSTy = Args->getElement(0)->getType()->getInOutObjectType()-> getCanonicalType(); CanType RHSTy = Args->getElement(1)->getType()->getCanonicalType(); if (LHSTy == RHSTy) OpType = Args->getElement(1)->getType(); LHSRange = Args->getElement(0)->getSourceRange(); RHSRange = Args->getElement(1)->getSourceRange(); } } bool Signed = false; StringRef Operator = "+"; switch (ID) { default: llvm_unreachable("Invalid case"); case llvm::Intrinsic::sadd_with_overflow: Signed = true; break; case llvm::Intrinsic::uadd_with_overflow: break; case llvm::Intrinsic::ssub_with_overflow: Operator = "-"; Signed = true; break; case llvm::Intrinsic::usub_with_overflow: Operator = "-"; break; case llvm::Intrinsic::smul_with_overflow: Operator = "*"; Signed = true; break; case llvm::Intrinsic::umul_with_overflow: Operator = "*"; break; } if (!OpType.isNull()) { diagnose(BI->getModule().getASTContext(), Loc.getSourceLoc(), diag::arithmetic_operation_overflow, LHSInt.toString(/*Radix*/ 10, Signed), Operator, RHSInt.toString(/*Radix*/ 10, Signed), OpType).highlight(LHSRange).highlight(RHSRange); } else { // If we cannot get the type info in an expected way, describe the type. diagnose(BI->getModule().getASTContext(), Loc.getSourceLoc(), diag::arithmetic_operation_overflow_generic_type, LHSInt.toString(/*Radix*/ 10, Signed), Operator, RHSInt.toString(/*Radix*/ 10, Signed), Signed, LHSInt.getBitWidth()).highlight(LHSRange).highlight(RHSRange); } ResultsInError = Optional<bool>(true); } return constructResultWithOverflowTuple(BI, Res, Overflow); }
static SILInstruction * constantFoldAndCheckIntegerConversions(BuiltinInst *BI, const BuiltinInfo &Builtin, Optional<bool> &ResultsInError) { assert(Builtin.ID == BuiltinValueKind::SToSCheckedTrunc || Builtin.ID == BuiltinValueKind::UToUCheckedTrunc || Builtin.ID == BuiltinValueKind::SToUCheckedTrunc || Builtin.ID == BuiltinValueKind::UToSCheckedTrunc || Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion); // Check if we are converting a constant integer. OperandValueArrayRef Args = BI->getArguments(); auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt SrcVal = V->getValue(); // Get source type and bit width. Type SrcTy = Builtin.Types[0]; uint32_t SrcBitWidth = Builtin.Types[0]->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Compute the destination (for SrcBitWidth < DestBitWidth) and enough info // to check for overflow. APInt Result; bool OverflowError; Type DstTy; // Process conversions signed <-> unsigned for same size integers. if (Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion) { DstTy = SrcTy; Result = SrcVal; // Report an error if the sign bit is set. OverflowError = SrcVal.isNegative(); // Process truncation from unsigned to signed. } else if (Builtin.ID != BuiltinValueKind::UToSCheckedTrunc) { assert(Builtin.Types.size() == 2); DstTy = Builtin.Types[1]; uint32_t DstBitWidth = DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Result = trunc_IntFrom_IntTo(Val) // For signed destination: // sext_IntFrom(Result) == Val ? Result : overflow_error // For signed destination: // zext_IntFrom(Result) == Val ? Result : overflow_error Result = SrcVal.trunc(DstBitWidth); // Get the signedness of the destination. bool Signed = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc); APInt Ext = Signed ? Result.sext(SrcBitWidth) : Result.zext(SrcBitWidth); OverflowError = (SrcVal != Ext); // Process the rest of truncations. } else { assert(Builtin.Types.size() == 2); DstTy = Builtin.Types[1]; uint32_t DstBitWidth = Builtin.Types[1]->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Compute the destination (for SrcBitWidth < DestBitWidth): // Result = trunc_IntTo(Val) // Trunc = trunc_'IntTo-1bit'(Val) // zext_IntFrom(Trunc) == Val ? Result : overflow_error Result = SrcVal.trunc(DstBitWidth); APInt TruncVal = SrcVal.trunc(DstBitWidth - 1); OverflowError = (SrcVal != TruncVal.zext(SrcBitWidth)); } // Check for overflow. if (OverflowError) { // If we are not asked to emit overflow diagnostics, just return nullptr on // overflow. if (!ResultsInError.hasValue()) return nullptr; SILLocation Loc = BI->getLoc(); SILModule &M = BI->getModule(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); Type UserSrcTy; Type UserDstTy; // Primitive heuristics to get the user-written type. // Eventually we might be able to use SILLocation (when it contains info // about inlined call chains). if (CE) { if (const TupleType *RTy = CE->getArg()->getType()->getAs<TupleType>()) { if (RTy->getNumElements() == 1) { UserSrcTy = RTy->getElementType(0); UserDstTy = CE->getType(); } } else { UserSrcTy = CE->getArg()->getType(); UserDstTy = CE->getType(); } } // Assume that we are converting from a literal if the Source size is // 2048. Is there a better way to identify conversions from literals? bool Literal = (SrcBitWidth == 2048); // FIXME: This will prevent hard error in cases the error is coming // from ObjC interoperability code. Currently, we treat NSUInteger as // Int. if (Loc.getSourceLoc().isInvalid()) { // Otherwise emit the appropriate diagnostic and set ResultsInError. if (Literal) diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_warn, UserDstTy.isNull() ? DstTy : UserDstTy); else diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_warn, UserSrcTy.isNull() ? SrcTy : UserSrcTy, UserDstTy.isNull() ? DstTy : UserDstTy); ResultsInError = Optional<bool>(true); return nullptr; } // Otherwise report the overflow error. if (Literal) { bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, SrcTySigned); // Try to print user-visible types if they are available. if (!UserDstTy.isNull()) { auto diagID = diag::integer_literal_overflow; // If this is a negative literal in an unsigned type, use a specific // diagnostic. if (SrcTySigned && !DstTySigned && SrcVal.isNegative()) diagID = diag::negative_integer_literal_overflow_unsigned; diagnose(M.getASTContext(), Loc.getSourceLoc(), diagID, UserDstTy, SrcAsString); // Otherwise, print the Builtin Types. } else { bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_builtin_types, DstTySigned, DstTy, SrcAsString); } } else { if (Builtin.ID == BuiltinValueKind::SUCheckedConversion) { diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_sign_error, UserDstTy.isNull() ? DstTy : UserDstTy); } else { // Try to print user-visible types if they are available. if (!UserSrcTy.isNull()) { diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow, UserSrcTy, UserDstTy); // Otherwise, print the Builtin Types. } else { // Since builtin types are sign-agnostic, print the signedness // separately. bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_builtin_types, SrcTySigned, SrcTy, DstTySigned, DstTy); } } } ResultsInError = Optional<bool>(true); return nullptr; } // The call to the builtin should be replaced with the constant value. return constructResultWithOverflowTuple(BI, Result, false); }