//--------------------------------------------------------- bool isPromotionCast(const CastExpr* CE) { QualType destType = CE->getType(); QualType srcType = CE->getSubExpr()->getType(); return (destType->isRealFloatingType() && srcType->isRealFloatingType()) || (destType->isSignedIntegerType() && srcType->isSignedIntegerType()) || (destType->isUnsignedIntegerType() && srcType->isUnsignedIntegerType()); }
static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { // Don't issue a fixit if there is already an initializer. if (VD->getInit()) return; // Suggest possible initialization (if any). const char *initialization = 0; QualType VariableTy = VD->getType().getCanonicalType(); if (VariableTy->isObjCObjectPointerType() || VariableTy->isBlockPointerType()) { // Check if 'nil' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) initialization = " = nil"; else initialization = " = 0"; } else if (VariableTy->isRealFloatingType()) initialization = " = 0.0"; else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) initialization = " = false"; else if (VariableTy->isEnumeralType()) return; else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { // Check if 'NULL' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) initialization = " = NULL"; else initialization = " = 0"; } else if (VariableTy->isScalarType()) initialization = " = 0"; if (initialization) { SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); S.Diag(loc, diag::note_var_fixit_add_initialization) << FixItHint::CreateInsertion(loc, initialization); } }
StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg Exprs, Expr *asmString, MultiExprArg clobbers, SourceLocation RParenLoc) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast<StringLiteral**>(constraints.data()); StringLiteral *AsmString = cast<StringLiteral>(asmString); StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data()); SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. if (!AsmString->isAscii()) return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) << AsmString->getSourceRange()); for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); StringRef OutputName; if (Names[i]) OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); if (!Context.getTargetInfo().validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; if (CheckAsmLValue(OutputExpr, *this)) return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_output) << OutputExpr->getSourceRange()); if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); OutputConstraintInfos.push_back(Info); } SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); StringRef InputName; if (Names[i]) InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(), NumOutputs, Info)) { return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_input_constraint) << Info.getConstraintStr()); } Expr *InputExpr = Exprs[i]; // Only allow void types for memory constraints. if (Info.allowsMemory() && !Info.allowsRegister()) { if (CheckAsmLValue(InputExpr, *this)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) return StmtError(); Exprs[i] = Result.get(); } if (Info.allowsRegister()) { if (InputExpr->getType()->isVoidType()) { return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) << InputExpr->getType() << Info.getConstraintStr() << InputExpr->getSourceRange()); } } InputConstraintInfos.push_back(Info); const Type *Ty = Exprs[i]->getType().getTypePtr(); if (Ty->isDependentType()) continue; if (!Ty->isVoidType() || !Info.allowsMemory()) if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); } // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); StringRef Clobber = Literal->getString(); if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } GCCAsmStmt *NS = new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) << AsmString->getSourceRange(); return StmtError(); } // Validate constraints and modifiers. for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; if (!Piece.isOperand()) continue; // Look for the correct constraint index. unsigned Idx = 0; unsigned ConstraintIdx = 0; for (unsigned i = 0, e = NS->getNumOutputs(); i != e; ++i, ++ConstraintIdx) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; if (Idx == Piece.getOperandNo()) break; ++Idx; if (Info.isReadWrite()) { if (Idx == Piece.getOperandNo()) break; ++Idx; } } for (unsigned i = 0, e = NS->getNumInputs(); i != e; ++i, ++ConstraintIdx) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; if (Idx == Piece.getOperandNo()) break; ++Idx; if (Info.isReadWrite()) { if (Idx == Piece.getOperandNo()) break; ++Idx; } } // Now that we have the right indexes go ahead and check. StringLiteral *Literal = Constraints[ConstraintIdx]; const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); if (Ty->isDependentType() || Ty->isIncompleteType()) continue; unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo() .validateConstraintModifier(Literal->getString(), Piece.getModifier(), Size)) Diag(Exprs[ConstraintIdx]->getLocStart(), diag::warn_asm_mismatched_size_modifier); } // Validate tied input operands for type mismatches. for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the // same size (int/long, int*/long, are ok etc). if (!Info.hasTiedOperand()) continue; unsigned TiedTo = Info.getTiedOperand(); unsigned InputOpNo = i+NumOutputs; Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[InputOpNo]; if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) continue; QualType InTy = InputExpr->getType(); QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. // Decide if the input and output are in the same domain (integer/ptr or // floating point. enum AsmDomain { AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; if (InTy->isIntegerType() || InTy->isPointerType()) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) InputDomain = AD_FP; else InputDomain = AD_Other; if (OutTy->isIntegerType() || OutTy->isPointerType()) OutputDomain = AD_Int; else if (OutTy->isRealFloatingType()) OutputDomain = AD_FP; else OutputDomain = AD_Other; // They are ok if they are the same size and in the same domain. This // allows tying things like: // void* to int* // void* to int if they are the same size. // double to long double if they are the same size. // uint64_t OutSize = Context.getTypeSize(OutTy); uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize && InputDomain == OutputDomain && InputDomain != AD_Other) continue; // If the smaller input/output operand is not mentioned in the asm string, // then we can promote the smaller one to a larger input and the asm string // won't notice. bool SmallerValueMentioned = false; // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (isOperandMentioned(InputOpNo, Pieces)) { // This is a use in the asm string of the smaller operand. Since we // codegen this by promoting to a wider value, the asm will get printed // "wrong". SmallerValueMentioned |= InSize < OutSize; } if (isOperandMentioned(TiedTo, Pieces)) { // If this is a reference to the output, and if the output is the larger // value, then it's ok because we'll promote the input to the larger type. SmallerValueMentioned |= OutSize < InSize; } // If the smaller value wasn't mentioned in the asm string, and if the // output was a register, just extend the shorter one to the size of the // larger one. if (!SmallerValueMentioned && InputDomain != AD_Other && OutputConstraintInfos[TiedTo].allowsRegister()) continue; // Either both of the operands were mentioned or the smaller one was // mentioned. One more special case that we'll allow: if the tied input is // integer, unmentioned, and is a constant, then we'll allow truncating it // down to the size of the destination. if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { CastKind castKind = (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).get(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; } Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() << InputExpr->getSourceRange(); return StmtError(); } return NS; }
StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg Exprs, Expr *asmString, MultiExprArg clobbers, SourceLocation RParenLoc) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast<StringLiteral**>(constraints.data()); StringLiteral *AsmString = cast<StringLiteral>(asmString); StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data()); SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. assert(AsmString->isAscii()); bool ValidateConstraints = DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl()); for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); StringRef OutputName; if (Names[i]) OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); if (ValidateConstraints && !Context.getTargetInfo().validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); ExprResult ER = CheckPlaceholderExpr(Exprs[i]); if (ER.isInvalid()) return StmtError(); Exprs[i] = ER.get(); // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(OutputExpr, *this)) return StmtError(); // Bitfield can't be referenced with a pointer. if (Info.allowsMemory() && OutputExpr->refersToBitField()) return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_bitfield_in_memory_constraint) << 1 << Info.getConstraintStr() << OutputExpr->getSourceRange()); OutputConstraintInfos.push_back(Info); // If this is dependent, just continue. if (OutputExpr->isTypeDependent()) continue; Expr::isModifiableLvalueResult IsLV = OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr); switch (IsLV) { case Expr::MLV_Valid: // Cool, this is an lvalue. break; case Expr::MLV_ArrayType: // This is OK too. break; case Expr::MLV_LValueCast: { const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context); if (!getLangOpts().HeinousExtensions) { Diag(LVal->getLocStart(), diag::err_invalid_asm_cast_lvalue) << OutputExpr->getSourceRange(); } else { Diag(LVal->getLocStart(), diag::warn_invalid_asm_cast_lvalue) << OutputExpr->getSourceRange(); } // Accept, even if we emitted an error diagnostic. break; } case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); default: return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_output) << OutputExpr->getSourceRange()); } unsigned Size = Context.getTypeSize(OutputExpr->getType()); if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), Size)) return StmtError(Diag(OutputExpr->getLocStart(), diag::err_asm_invalid_output_size) << Info.getConstraintStr()); } SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); StringRef InputName; if (Names[i]) InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); if (ValidateConstraints && !Context.getTargetInfo().validateInputConstraint( OutputConstraintInfos.data(), NumOutputs, Info)) { return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_input_constraint) << Info.getConstraintStr()); } ExprResult ER = CheckPlaceholderExpr(Exprs[i]); if (ER.isInvalid()) return StmtError(); Exprs[i] = ER.get(); Expr *InputExpr = Exprs[i]; // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(InputExpr, *this)) return StmtError(); // Bitfield can't be referenced with a pointer. if (Info.allowsMemory() && InputExpr->refersToBitField()) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_bitfield_in_memory_constraint) << 0 << Info.getConstraintStr() << InputExpr->getSourceRange()); // Only allow void types for memory constraints. if (Info.allowsMemory() && !Info.allowsRegister()) { if (CheckAsmLValue(InputExpr, *this)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { if (!InputExpr->isValueDependent()) { llvm::APSInt Result; if (!InputExpr->EvaluateAsInt(Result, Context)) return StmtError( Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected) << Info.getConstraintStr() << InputExpr->getSourceRange()); if (!Info.isValidAsmImmediate(Result)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_invalid_asm_value_for_constraint) << Result.toString(10) << Info.getConstraintStr() << InputExpr->getSourceRange()); } } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) return StmtError(); Exprs[i] = Result.get(); } if (Info.allowsRegister()) { if (InputExpr->getType()->isVoidType()) { return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) << InputExpr->getType() << Info.getConstraintStr() << InputExpr->getSourceRange()); } } InputConstraintInfos.push_back(Info); const Type *Ty = Exprs[i]->getType().getTypePtr(); if (Ty->isDependentType()) continue; if (!Ty->isVoidType() || !Info.allowsMemory()) if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) return StmtError(Diag(InputExpr->getLocStart(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); } // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; assert(Literal->isAscii()); StringRef Clobber = Literal->getString(); if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } GCCAsmStmt *NS = new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) << AsmString->getSourceRange(); return StmtError(); } // Validate constraints and modifiers. for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; if (!Piece.isOperand()) continue; // Look for the correct constraint index. unsigned ConstraintIdx = Piece.getOperandNo(); unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); // Look for the (ConstraintIdx - NumOperands + 1)th constraint with // modifier '+'. if (ConstraintIdx >= NumOperands) { unsigned I = 0, E = NS->getNumOutputs(); for (unsigned Cnt = ConstraintIdx - NumOperands; I != E; ++I) if (OutputConstraintInfos[I].isReadWrite() && Cnt-- == 0) { ConstraintIdx = I; break; } assert(I != E && "Invalid operand number should have been caught in " " AnalyzeAsmString"); } // Now that we have the right indexes go ahead and check. StringLiteral *Literal = Constraints[ConstraintIdx]; const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); if (Ty->isDependentType() || Ty->isIncompleteType()) continue; unsigned Size = Context.getTypeSize(Ty); std::string SuggestedModifier; if (!Context.getTargetInfo().validateConstraintModifier( Literal->getString(), Piece.getModifier(), Size, SuggestedModifier)) { Diag(Exprs[ConstraintIdx]->getLocStart(), diag::warn_asm_mismatched_size_modifier); if (!SuggestedModifier.empty()) { auto B = Diag(Piece.getRange().getBegin(), diag::note_asm_missing_constraint_modifier) << SuggestedModifier; SuggestedModifier = "%" + SuggestedModifier + Piece.getString(); B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier)); } } } // Validate tied input operands for type mismatches. unsigned NumAlternatives = ~0U; for (unsigned i = 0, e = OutputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; StringRef ConstraintStr = Info.getConstraintStr(); unsigned AltCount = ConstraintStr.count(',') + 1; if (NumAlternatives == ~0U) NumAlternatives = AltCount; else if (NumAlternatives != AltCount) return StmtError(Diag(NS->getOutputExpr(i)->getLocStart(), diag::err_asm_unexpected_constraint_alternatives) << NumAlternatives << AltCount); } for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; StringRef ConstraintStr = Info.getConstraintStr(); unsigned AltCount = ConstraintStr.count(',') + 1; if (NumAlternatives == ~0U) NumAlternatives = AltCount; else if (NumAlternatives != AltCount) return StmtError(Diag(NS->getInputExpr(i)->getLocStart(), diag::err_asm_unexpected_constraint_alternatives) << NumAlternatives << AltCount); // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the // same size (int/long, int*/long, are ok etc). if (!Info.hasTiedOperand()) continue; unsigned TiedTo = Info.getTiedOperand(); unsigned InputOpNo = i+NumOutputs; Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[InputOpNo]; if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) continue; QualType InTy = InputExpr->getType(); QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. // Decide if the input and output are in the same domain (integer/ptr or // floating point. enum AsmDomain { AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; if (InTy->isIntegerType() || InTy->isPointerType()) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) InputDomain = AD_FP; else InputDomain = AD_Other; if (OutTy->isIntegerType() || OutTy->isPointerType()) OutputDomain = AD_Int; else if (OutTy->isRealFloatingType()) OutputDomain = AD_FP; else OutputDomain = AD_Other; // They are ok if they are the same size and in the same domain. This // allows tying things like: // void* to int* // void* to int if they are the same size. // double to long double if they are the same size. // uint64_t OutSize = Context.getTypeSize(OutTy); uint64_t InSize = Context.getTypeSize(InTy); if (OutSize == InSize && InputDomain == OutputDomain && InputDomain != AD_Other) continue; // If the smaller input/output operand is not mentioned in the asm string, // then we can promote the smaller one to a larger input and the asm string // won't notice. bool SmallerValueMentioned = false; // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (isOperandMentioned(InputOpNo, Pieces)) { // This is a use in the asm string of the smaller operand. Since we // codegen this by promoting to a wider value, the asm will get printed // "wrong". SmallerValueMentioned |= InSize < OutSize; } if (isOperandMentioned(TiedTo, Pieces)) { // If this is a reference to the output, and if the output is the larger // value, then it's ok because we'll promote the input to the larger type. SmallerValueMentioned |= OutSize < InSize; } // If the smaller value wasn't mentioned in the asm string, and if the // output was a register, just extend the shorter one to the size of the // larger one. if (!SmallerValueMentioned && InputDomain != AD_Other && OutputConstraintInfos[TiedTo].allowsRegister()) continue; // Either both of the operands were mentioned or the smaller one was // mentioned. One more special case that we'll allow: if the tied input is // integer, unmentioned, and is a constant, then we'll allow truncating it // down to the size of the destination. if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { CastKind castKind = (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).get(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; } Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() << InputExpr->getSourceRange(); return StmtError(); } return NS; }
bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, bool IsObjCLiteral) { // %n is different from other conversion specifiers; don't try to fix it. if (CS.getKind() == ConversionSpecifier::nArg) return false; // Handle Objective-C objects first. Note that while the '%@' specifier will // not warn for structure pointer or void pointer arguments (because that's // how CoreFoundation objects are implemented), we only show a fixit for '%@' // if we know it's an object (block, id, class, or __attribute__((NSObject))). if (QT->isObjCRetainableType()) { if (!IsObjCLiteral) return false; CS.setKind(ConversionSpecifier::ObjCObjArg); // Disable irrelevant flags HasThousandsGrouping = false; HasPlusPrefix = false; HasSpacePrefix = false; HasAlternativeForm = false; HasLeadingZeroes = false; Precision.setHowSpecified(OptionalAmount::NotSpecified); LM.setKind(LengthModifier::None); return true; } // Handle strings next (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; HasLeadingZeroes = 0; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); else LM.setKind(LengthModifier::None); return true; } // If it's an enum, get its underlying type. if (const EnumType *ETy = QT->getAs<EnumType>()) QT = ETy->getDecl()->getIntegerType(); // We can only work with builtin types. const BuiltinType *BT = QT->getAs<BuiltinType>(); if (!BT) return false; // Set length modifier switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::WChar_U: case BuiltinType::WChar_S: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::UInt128: case BuiltinType::Int128: case BuiltinType::Half: case BuiltinType::Float128: // Various types which are non-trivial to correct. return false; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" #define SIGNED_TYPE(Id, SingletonId) #define UNSIGNED_TYPE(Id, SingletonId) #define FLOATING_TYPE(Id, SingletonId) #define BUILTIN_TYPE(Id, SingletonId) \ case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" // Misc other stuff which doesn't make sense here. return false; case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: case BuiltinType::Double: LM.setKind(LengthModifier::None); break; case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: LM.setKind(LengthModifier::AsChar); break; case BuiltinType::Short: case BuiltinType::UShort: LM.setKind(LengthModifier::AsShort); break; case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); break; case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; } // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) namedTypeToLengthModifier(QT, LM); // If fixing the length modifier was enough, we might be done. if (hasValidLengthModifier(Ctx.getTargetInfo())) { // If we're going to offer a fix anyway, make sure the sign matches. switch (CS.getKind()) { case ConversionSpecifier::uArg: case ConversionSpecifier::UArg: if (QT->isSignedIntegerType()) CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); break; case ConversionSpecifier::dArg: case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: if (QT->isUnsignedIntegerType() && !HasPlusPrefix) CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); break; default: // Other specifiers do not have signed/unsigned variants. break; } const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); if (ATR.isValid() && ATR.matchesType(Ctx, QT)) return true; } // Set conversion specifier and disable any flags which do not apply to it. // Let typedefs to char fall through to int, as %c is silly for uint8_t. if (!isa<TypedefType>(QT) && QT->isCharType()) { CS.setKind(ConversionSpecifier::cArg); LM.setKind(LengthModifier::None); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { llvm_unreachable("Unexpected type"); } return true; }
bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt) { if (!QT->isPointerType()) return false; QualType PT = QT->getPointeeType(); const BuiltinType *BT = PT->getAs<BuiltinType>(); if (!BT) return false; // Pointer to a character. if (PT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::sArg); if (PT->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); else LM.setKind(LengthModifier::None); return true; } // Figure out the length modifier. switch (BT->getKind()) { // no modifier case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: LM.setKind(LengthModifier::None); break; // hh case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: LM.setKind(LengthModifier::AsChar); break; // h case BuiltinType::Short: case BuiltinType::UShort: LM.setKind(LengthModifier::AsShort); break; // l case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::Double: LM.setKind(LengthModifier::AsLong); break; // ll case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; // L case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; // Don't know. default: return false; } // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) { const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier(); if (Identifier->getName() == "size_t") { LM.setKind(LengthModifier::AsSizeT); } else if (Identifier->getName() == "ssize_t") { // Not C99, but common in Unix. LM.setKind(LengthModifier::AsSizeT); } else if (Identifier->getName() == "intmax_t") { LM.setKind(LengthModifier::AsIntMax); } else if (Identifier->getName() == "uintmax_t") { LM.setKind(LengthModifier::AsIntMax); } else if (Identifier->getName() == "ptrdiff_t") { LM.setKind(LengthModifier::AsPtrDiff); } } // Figure out the conversion specifier. if (PT->isRealFloatingType()) CS.setKind(ConversionSpecifier::fArg); else if (PT->isSignedIntegerType()) CS.setKind(ConversionSpecifier::dArg); else if (PT->isUnsignedIntegerType()) { // Preserve the original formatting, e.g. 'X', 'o'. if (!CS.isUIntArg()) { CS.setKind(ConversionSpecifier::uArg); } } else llvm_unreachable("Unexpected type"); return true; }
bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; HasLeadingZeroes = 0; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); else LM.setKind(LengthModifier::None); return true; } // We can only work with builtin types. const BuiltinType *BT = QT->getAs<BuiltinType>(); if (!BT) return false; // Set length modifier switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::WChar_U: case BuiltinType::WChar_S: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::UInt128: case BuiltinType::Int128: case BuiltinType::Half: // Various types which are non-trivial to correct. return false; #define SIGNED_TYPE(Id, SingletonId) #define UNSIGNED_TYPE(Id, SingletonId) #define FLOATING_TYPE(Id, SingletonId) #define BUILTIN_TYPE(Id, SingletonId) \ case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" // Misc other stuff which doesn't make sense here. return false; case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: case BuiltinType::Double: LM.setKind(LengthModifier::None); break; case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: LM.setKind(LengthModifier::AsChar); break; case BuiltinType::Short: case BuiltinType::UShort: LM.setKind(LengthModifier::AsShort); break; case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); break; case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; } // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) { const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier(); if (Identifier->getName() == "size_t") { LM.setKind(LengthModifier::AsSizeT); } else if (Identifier->getName() == "ssize_t") { // Not C99, but common in Unix. LM.setKind(LengthModifier::AsSizeT); } else if (Identifier->getName() == "intmax_t") { LM.setKind(LengthModifier::AsIntMax); } else if (Identifier->getName() == "uintmax_t") { LM.setKind(LengthModifier::AsIntMax); } else if (Identifier->getName() == "ptrdiff_t") { LM.setKind(LengthModifier::AsPtrDiff); } } // Set conversion specifier and disable any flags which do not apply to it. // Let typedefs to char fall through to int, as %c is silly for uint8_t. if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::cArg); LM.setKind(LengthModifier::None); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { // Preserve the original formatting, e.g. 'X', 'o'. if (!cast<PrintfConversionSpecifier>(CS).isUIntArg()) CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { llvm_unreachable("Unexpected type"); } return true; }
bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx) { if (!QT->isPointerType()) return false; // %n is different from other conversion specifiers; don't try to fix it. if (CS.getKind() == ConversionSpecifier::nArg) return false; QualType PT = QT->getPointeeType(); // If it's an enum, get its underlying type. if (const EnumType *ETy = QT->getAs<EnumType>()) QT = ETy->getDecl()->getIntegerType(); const BuiltinType *BT = PT->getAs<BuiltinType>(); if (!BT) return false; // Pointer to a character. if (PT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::sArg); if (PT->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); else LM.setKind(LengthModifier::None); return true; } // Figure out the length modifier. switch (BT->getKind()) { // no modifier case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: LM.setKind(LengthModifier::None); break; // hh case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: LM.setKind(LengthModifier::AsChar); break; // h case BuiltinType::Short: case BuiltinType::UShort: LM.setKind(LengthModifier::AsShort); break; // l case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::Double: LM.setKind(LengthModifier::AsLong); break; // ll case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; // L case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; // Don't know. default: return false; } // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. if (isa<TypedefType>(PT) && (LangOpt.F90 || LangOpt.F90)) namedTypeToLengthModifier(PT, LM); // If fixing the length modifier was enough, we are done. if (hasValidLengthModifier(Ctx.getTargetInfo())) { const analyze_scanf::ArgType &AT = getArgType(Ctx); if (AT.isValid() && AT.matchesType(Ctx, QT)) return true; } // Figure out the conversion specifier. if (PT->isRealFloatingType()) CS.setKind(ConversionSpecifier::fArg); else if (PT->isSignedIntegerType()) CS.setKind(ConversionSpecifier::dArg); else if (PT->isUnsignedIntegerType()) CS.setKind(ConversionSpecifier::uArg); else llvm_unreachable("Unexpected type"); return true; }
LValue ComplexExprEmitter:: EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&), RValue &Val) { TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); QualType LHSTy = E->getLHS()->getType(); if (const AtomicType *AT = LHSTy->getAs<AtomicType>()) LHSTy = AT->getValueType(); BinOpInfo OpInfo; // Load the RHS and LHS operands. // __block variables need to have the rhs evaluated first, plus this should // improve codegen a little. OpInfo.Ty = E->getComputationResultType(); QualType ComplexElementTy = cast<ComplexType>(OpInfo.Ty)->getElementType(); // The RHS should have been converted to the computation type. if (E->getRHS()->getType()->isRealFloatingType()) { assert( CGF.getContext() .hasSameUnqualifiedType(ComplexElementTy, E->getRHS()->getType())); OpInfo.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr); } else { assert(CGF.getContext() .hasSameUnqualifiedType(OpInfo.Ty, E->getRHS()->getType())); OpInfo.RHS = Visit(E->getRHS()); } LValue LHS = CGF.EmitLValue(E->getLHS()); // Load from the l-value and convert it. if (LHSTy->isAnyComplexType()) { ComplexPairTy LHSVal = EmitLoadOfLValue(LHS, E->getExprLoc()); OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty); } else { llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS, E->getExprLoc()); // For floating point real operands we can directly pass the scalar form // to the binary operator emission and potentially get more efficient code. if (LHSTy->isRealFloatingType()) { if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy)) LHSVal = CGF.EmitScalarConversion(LHSVal, LHSTy, ComplexElementTy); OpInfo.LHS = ComplexPairTy(LHSVal, nullptr); } else { OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty); } } // Expand the binary operator. ComplexPairTy Result = (this->*Func)(OpInfo); // Truncate the result and store it into the LHS lvalue. if (LHSTy->isAnyComplexType()) { ComplexPairTy ResVal = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); EmitStoreOfComplex(ResVal, LHS, /*isInit*/ false); Val = RValue::getComplex(ResVal); } else { llvm::Value *ResVal = CGF.EmitComplexToScalarConversion(Result, OpInfo.Ty, LHSTy); CGF.EmitStoreOfScalar(ResVal, LHS, /*isInit*/ false); Val = RValue::get(ResVal); } return LHS; }
bool PrintfSpecifier::fixType(QualType QT) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; HasLeadingZeroes = 0; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); return true; } // We can only work with builtin types. if (!QT->isBuiltinType()) return false; // Everything else should be a base type const BuiltinType *BT = QT->getAs<BuiltinType>(); // Set length modifier switch (BT->getKind()) { default: // The rest of the conversions are either optional or for non-builtin types LM.setKind(LengthModifier::None); break; case BuiltinType::WChar: case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); break; case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; } // Set conversion specifier and disable any flags which do not apply to it. if (QT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::cArg); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isPointerType()) { CS.setKind(ConversionSpecifier::pArg); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { return false; } return true; }
bool PrintfSpecifier::fixType(QualType QT) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; HasLeadingZeroes = 0; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); return true; } // We can only work with builtin types. if (!QT->isBuiltinType()) return false; // Everything else should be a base type const BuiltinType *BT = QT->getAs<BuiltinType>(); // Set length modifier switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::WChar_U: case BuiltinType::WChar_S: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::UInt128: case BuiltinType::Int128: // Integral types which are non-trivial to correct. return false; case BuiltinType::Void: case BuiltinType::NullPtr: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: case BuiltinType::Dependent: case BuiltinType::Overload: case BuiltinType::BoundMember: case BuiltinType::UnknownAny: // Misc other stuff which doesn't make sense here. return false; case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: case BuiltinType::Double: LM.setKind(LengthModifier::None); break; case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: LM.setKind(LengthModifier::AsChar); break; case BuiltinType::Short: case BuiltinType::UShort: LM.setKind(LengthModifier::AsShort); break; case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); break; case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; } // Set conversion specifier and disable any flags which do not apply to it. // Let typedefs to char fall through to int, as %c is silly for uint8_t. if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::cArg); LM.setKind(LengthModifier::None); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { // Preserve the original formatting, e.g. 'X', 'o'. if (!cast<PrintfConversionSpecifier>(CS).isUIntArg()) CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { llvm_unreachable("Unexpected type"); } return true; }