static void HandleMSP430InterruptAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr.getName() << 1; return; } if (!Attr.isArgExpr(0)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() << AANT_ArgumentIntegerConstant; return; } // FIXME: Check for decl - it should be void ()(void). Expr *NumParamsExpr = Attr.getArgAsExpr(0); llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() << AANT_ArgumentIntegerConstant << NumParamsExpr->getSourceRange(); return; } unsigned Num = NumParams.getLimitedValue(255); if ((Num & 1) || Num > 30) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) << "interrupt" << (int)NumParams.getSExtValue() << NumParamsExpr->getSourceRange(); return; } d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num)); d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); }
// CWE-467: Use of sizeof() on a Pointer Type void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { if (E->getKind() != UETT_SizeOf) return; // If an explicit type is used in the code, usually the coder knows what he is // doing. if (E->isArgumentType()) return; QualType T = E->getTypeOfArgument(); if (T->isPointerType()) { // Many false positives have the form 'sizeof *p'. This is reasonable // because people know what they are doing when they intentionally // dereference the pointer. Expr *ArgEx = E->getArgumentExpr(); if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) return; PathDiagnosticLocation ELoc = PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), Checker, "Potential unintended use of sizeof() on pointer type", categories::LogicError, "The code calls sizeof() on a pointer type. " "This can produce an unexpected result.", ELoc, ArgEx->getSourceRange()); } }
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ // If this type is already address space qualified, reject it. // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers // for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); return; } // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt addrSpace(32); if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); return; } unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()); Type = S.Context.getAddrSpaceQualType(Type, ASIdx); }
void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { Expr *Init = VD->getInit(); if (!Init) return; // Pattern match for: // llvm::StringRef x = call() (where call returns std::string) if (!IsLLVMStringRef(VD->getType())) return; CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init); if (!Ex1) return; CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr()); if (!Ex2 || Ex2->getNumArgs() != 1) return; ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0)); if (!Ex3) return; CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr()); if (!Ex4 || Ex4->getNumArgs() != 1) return; ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0)); if (!Ex5) return; CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr()); if (!Ex6 || !IsStdString(Ex6->getType())) return; // Okay, badness! Report an error. const char *desc = "StringRef should not be bound to temporary " "std::string that it outlives"; BR.EmitBasicReport(desc, "LLVM Conventions", desc, VD->getLocStart(), Init->getSourceRange()); }
// CWE-467: Use of sizeof() on a Pointer Type void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!E->isSizeOf()) return; // If an explicit type is used in the code, usually the coder knows what he is // doing. if (E->isArgumentType()) return; QualType T = E->getTypeOfArgument(); if (T->isPointerType()) { // Many false positives have the form 'sizeof *p'. This is reasonable // because people know what they are doing when they intentionally // dereference the pointer. Expr *ArgEx = E->getArgumentExpr(); if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) return; SourceRange R = ArgEx->getSourceRange(); BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type", "Logic", "The code calls sizeof() on a pointer type. " "This can produce an unexpected result.", E->getLocStart(), &R, 1); } }
void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng, Stmt *Condition, void *tag) { const GRState *state = Builder.getState(); SVal X = state->getSVal(Condition); if (X.isUndef()) { ExplodedNode *N = Builder.generateNode(state, true); if (N) { N->markAsSink(); if (!BT) BT = new BuiltinBug("Branch condition evaluates to a garbage value"); // What's going on here: we want to highlight the subexpression of the // condition that is the most likely source of the "uninitialized // branch condition." We do a recursive walk of the condition's // subexpressions and roughly look for the most nested subexpression // that binds to Undefined. We then highlight that expression's range. BlockEdge B = cast<BlockEdge>(N->getLocation()); Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition()); assert (Ex && "Block must have a terminator."); // Get the predecessor node and check if is a PostStmt with the Stmt // being the terminator condition. We want to inspect the state // of that node instead because it will contain main information about // the subexpressions. assert (!N->pred_empty()); // Note: any predecessor will do. They should have identical state, // since all the BlockEdge did was act as an error sink since the value // had to already be undefined. ExplodedNode *PrevN = *N->pred_begin(); ProgramPoint P = PrevN->getLocation(); const GRState* St = N->getState(); if (PostStmt* PS = dyn_cast<PostStmt>(&P)) if (PS->getStmt() == Ex) St = PrevN->getState(); FindUndefExpr FindIt(Eng.getStateManager(), St); Ex = FindIt.FindExpr(Ex); // Emit the bug report. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); R->addRange(Ex->getSourceRange()); Eng.getBugReporter().EmitReport(R); } Builder.markInfeasible(true); Builder.markInfeasible(false); } }
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, ExprArg Operand) { // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type // having a single conversion function to a pointer type. The result has // type void." // DR599 amends "pointer type" to "pointer to object type" in both cases. Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (Type->isRecordType()) { // FIXME: Find that one conversion function and amend the type. } if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); QualType Pointee = Type->getAsPointerType()->getPointeeType(); if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex->getSourceRange())) return ExprError(); // FIXME: Look up the correct operator delete overload and pass a pointer // along. // FIXME: Check access and ambiguity of operator delete and destructor. } Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, 0, Ex, StartLoc)); }
bool ParseFunctionCall(FunctionEvent *Event, BinaryOperator *Bop, vector<ValueDecl*>& References, ASTContext& Ctx) { // TODO: better distinguishing between callee and/or caller Event->set_context(FunctionEvent::Callee); // Since we might care about the return value, we must instrument exiting // the function rather than entering it. Event->set_direction(FunctionEvent::Exit); Expr *LHS = Bop->getLHS(); bool LHSisICE = LHS->isIntegerConstantExpr(Ctx); Expr *RHS = Bop->getRHS(); if (!(LHSisICE ^ RHS->isIntegerConstantExpr(Ctx))) { Report("One of {LHS,RHS} must be ICE", Bop->getLocStart(), Ctx) << Bop->getSourceRange(); return false; } Expr *RetVal = (LHSisICE ? LHS : RHS); Expr *FnCall = (LHSisICE ? RHS : LHS); if (!ParseArgument(Event->mutable_expectedreturnvalue(), RetVal, References, Ctx)) return false; auto FnCallExpr = dyn_cast<CallExpr>(FnCall); if (!FnCallExpr) { Report("Not a function call", FnCall->getLocStart(), Ctx) << FnCall->getSourceRange(); return false; } auto Fn = FnCallExpr->getDirectCallee(); if (!Fn) { Report("Not a direct function call", FnCallExpr->getLocStart(), Ctx) << FnCallExpr->getSourceRange(); return false; } if (!ParseFunctionRef(Event->mutable_function(), Fn, Ctx)) return false; for (auto I = FnCallExpr->arg_begin(); I != FnCallExpr->arg_end(); ++I) { if (!ParseArgument(Event->add_argument(), I->IgnoreImplicit(), References, Ctx)) return false; } return true; }
void DanglingDelegateChecker::verifyIvarDynamicStateAgainstStaticFacts(const Expr &expr, const ObjCIvarDecl *ivarDecl, CheckerContext &context) const { // first retrieve the dangerous 'static' facts we know about the ivar if (!ivarDecl) { return; } const ObjCImplFacts *facts = getCurrentFacts(getCurrentTopClassInterface(context)); if (!facts || facts->_ivarFactsMap.find(ivarDecl) == facts->_ivarFactsMap.end()) { // not an interesting ivar (no entry) return; } const IvarFacts &ivarFacts = facts->_ivarFactsMap.at(ivarDecl); std::string ivarName = ivarDecl->getNameAsString(); // second retrieve the current 'dynamic' state of the ivar ProgramStateRef state = context.getState(); const IvarDynamicState emptyIds; const IvarDynamicState *ids = state->get<IvarMap>(ivarDecl); if (!ids) { ids = &emptyIds; } // Verify that all the dangerous properties have been cleared const StringSet &dangerousProperties = ivarFacts._mayStoreSelfInUnsafeProperty; const StringSet &clearedProperties = ids->_assignPropertyWasCleared; const std::function<void(StringRef)> emitBug([this, &context, &expr](StringRef str) { BugReport *report = new BugReport(*_bugType, str, context.getPredecessor()); report->addRange(expr.getSourceRange()); context.emitReport(report); }); verifyAndReportDangerousProperties(dangerousProperties, clearedProperties, ivarName, ivarDecl->getType(), "", emitBug); // Verify that the object in the ivar is not 'observing' self (TODO) // if (ivarFacts._mayObserveSelf && !ids->_observerWasCleared) { // } // Verify that the object in the ivar is not 'targeting' self (TODO) // if (ivarFacts._mayTargetSelf && !ids->_targetWasCleared) { // } }
ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, tok::TokenKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc) { // LHS and RHS must be cast-expressions. We allow an arbitrary expression // in the parser and reduce down to just cast-expressions here. CheckFoldOperand(*this, LHS); CheckFoldOperand(*this, RHS); auto DiscardOperands = [&] { CorrectDelayedTyposInExpr(LHS); CorrectDelayedTyposInExpr(RHS); }; // [expr.prim.fold]p3: // In a binary fold, op1 and op2 shall be the same fold-operator, and // either e1 shall contain an unexpanded parameter pack or e2 shall contain // an unexpanded parameter pack, but not both. if (LHS && RHS && LHS->containsUnexpandedParameterPack() == RHS->containsUnexpandedParameterPack()) { DiscardOperands(); return Diag(EllipsisLoc, LHS->containsUnexpandedParameterPack() ? diag::err_fold_expression_packs_both_sides : diag::err_pack_expansion_without_parameter_packs) << LHS->getSourceRange() << RHS->getSourceRange(); } // [expr.prim.fold]p2: // In a unary fold, the cast-expression shall contain an unexpanded // parameter pack. if (!LHS || !RHS) { Expr *Pack = LHS ? LHS : RHS; assert(Pack && "fold expression with neither LHS nor RHS"); DiscardOperands(); if (!Pack->containsUnexpandedParameterPack()) return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << Pack->getSourceRange(); } BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator); return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc); }
static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's // useful for OpenCL 1.x too and doesn't require HW support. // opencl_unroll_hint can have 0 arguments (compiler // determines unrolling factor) or 1 argument (the unroll factor provided // by the user). unsigned NumArgs = A.getNumArgs(); if (NumArgs > 1) { S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A << 1; return nullptr; } unsigned UnrollFactor = 0; if (NumArgs == 1) { Expr *E = A.getArgAsExpr(0); llvm::APSInt ArgVal(32); if (!E->isIntegerConstantExpr(ArgVal, S.Context)) { S.Diag(A.getLoc(), diag::err_attribute_argument_type) << A << AANT_ArgumentIntegerConstant << E->getSourceRange(); return nullptr; } int Val = ArgVal.getSExtValue(); if (Val <= 0) { S.Diag(A.getRange().getBegin(), diag::err_attribute_requires_positive_integer) << A; return nullptr; } UnrollFactor = Val; } return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor); }
void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { Expr *Init = VD->getInit(); if (!Init) return; // Pattern match for: // StringRef x = call() (where call returns std::string) if (!IsLLVMStringRef(VD->getType())) return; ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init); if (!Ex1) return; CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr()); if (!Ex2 || Ex2->getNumArgs() != 1) return; ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0)); if (!Ex3) return; CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr()); if (!Ex4 || Ex4->getNumArgs() != 1) return; ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0)); if (!Ex5) return; CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr()); if (!Ex6 || !IsStdString(Ex6->getType())) return; // Okay, badness! Report an error. const char *desc = "StringRef should not be bound to temporary " "std::string that it outlives"; PathDiagnosticLocation VDLoc = PathDiagnosticLocation::createBegin(VD, BR.getSourceManager()); BR.EmitBasicReport(DeclWithIssue, desc, "LLVM Conventions", desc, VDLoc, Init->getSourceRange()); }
/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: /// @code new (memory) int[size][4] @endcode /// or /// @code ::new Foo(23, "hello") @endcode /// For the interpretation of this heap of arguments, consult the base version. Action::OwningExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { Expr *ArraySize = 0; unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); Skip = 1; } QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); if (D.getInvalidType()) return ExprError(); if (CheckAllocatedType(AllocType, D)) return ExprError(); QualType ResultType = AllocType->isDependentType() ? Context.DependentTy : Context.getPointerType(AllocType); // That every array dimension except the first is constant was already // checked by the type check above. // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { QualType SizeType = ArraySize->getType(); if (!SizeType->isIntegralType() && !SizeType->isEnumeralType()) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_array_size_not_integral) << SizeType << ArraySize->getSourceRange()); // Let's see if this is a constant < 0. If so, we reject it out of hand. // We don't care about special rules, so we tell the machinery it's not // evaluated - it gives us a result in more cases. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { if (Value < llvm::APSInt( llvm::APInt::getNullValue(Value.getBitWidth()), false)) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } } } FunctionDecl *OperatorNew = 0; FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- // C++ 5.3.4p15 // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid) // the object is not initialized. If the object, or any part of it, is // const-qualified, it's an error. // 2) If T is a POD and there's an empty initializer, the object is value- // initialized. // 3) If T is a POD and there's one initializer argument, the object is copy- // constructed. // 4) If T is a POD and there's more initializer arguments, it's an error. // 5) If T is not a POD, the initializer arguments are used as constructor // arguments. // // Or by the C++0x formulation: // 1) If there's no initializer, the object is default-initialized according // to C++0x rules. // 2) Otherwise, the object is direct-initialized. CXXConstructorDecl *Constructor = 0; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); unsigned NumConsArgs = ConstructorArgs.size(); if (AllocType->isDependentType()) { // Skip all the checks. } // FIXME: Should check for primitive/aggregate here, not record. else if (const RecordType *RT = AllocType->getAsRecordType()) { // FIXME: This is incorrect for when there is an empty initializer and // no user-defined constructor. Must zero-initialize, not default-construct. Constructor = PerformInitializationByConstructor( AllocType, ConsArgs, NumConsArgs, D.getSourceRange().getBegin(), SourceRange(D.getSourceRange().getBegin(), ConstructorRParen), RT->getDecl()->getDeclName(), NumConsArgs != 0 ? IK_Direct : IK_Default); if (!Constructor) return ExprError(); } else { if (!Init) { // FIXME: Check that no subpart is const. if (AllocType.isConstQualified()) return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const) << D.getSourceRange()); } else if (NumConsArgs == 0) { // Object is value-initialized. Do nothing. } else if (NumConsArgs == 1) { // Object is direct-initialized. // FIXME: WHAT DeclarationName do we pass in here? if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc, DeclarationName() /*AllocType.getAsString()*/, /*DirectInit=*/true)) return ExprError(); } else { return ExprError(Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg) << SourceRange(ConstructorLParen, ConstructorRParen)); } } // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) PlacementArgs.release(); ConstructorArgs.release(); return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType, StartLoc, Init ? ConstructorRParen : SourceLocation())); }
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; }
/// \brief Build an Objective-C instance message expression. /// /// This routine takes care of both normal instance messages and /// instance messages to the superclass instance. /// /// \param Receiver The expression that computes the object that will /// receive this message. This may be empty, in which case we are /// sending to the superclass instance and \p SuperLoc must be a valid /// source location. /// /// \param ReceiverType The (static) type of the object receiving the /// message. When a \p Receiver expression is provided, this is the /// same type as that expression. For a superclass instance send, this /// is a pointer to the type of the superclass. /// /// \param SuperLoc The location of the "super" keyword in a /// superclass instance message. /// /// \param Sel The selector to which the message is being sent. /// /// \param Method The method that this instance message is invoking, if /// already known. /// /// \param LBracLoc The location of the opening square bracket ']'. /// /// \param RBrac The location of the closing square bracket ']'. /// /// \param Args The message arguments. Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, SourceLocation RBracLoc, MultiExprArg ArgsIn) { // If we have a receiver expression, perform appropriate promotions // and determine receiver type. Expr *Receiver = ReceiverE.takeAs<Expr>(); if (Receiver) { if (Receiver->isTypeDependent()) { // If the receiver is type-dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, LBracLoc, Receiver, Sel, /*Method=*/0, Args, NumArgs, RBracLoc)); } // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. DefaultFunctionArrayLvalueConversion(Receiver); ReceiverType = Receiver->getType(); } // The location of the receiver. SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); if (!Method) { // Handle messages to id. bool receiverIsId = ReceiverType->isObjCIdType(); if (receiverIsId || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), receiverIsId); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), receiverIsId); } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { // First check the public methods in the class interface. Method = ClassDecl->lookupClassMethod(Sel); if (!Method) Method = LookupPrivateClassMethod(Sel, ClassDecl); // FIXME: if we still haven't found a method, we need to look in // protocols (if we have qualifiers). } if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); if (!Method) { // If no class (factory) method was found, check if an _instance_ // method of the same name exists in the root class only. Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); if (Method) if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { if (ID->getSuperClass()) Diag(Loc, diag::warn_root_inst_method_not_found) << Sel << SourceRange(LBracLoc, RBracLoc); } } } } } else { ObjCInterfaceDecl* ClassDecl = 0; // We allow sending a message to a qualified ID ("id<foo>"), which is ok as // long as one of the protocols implements the selector (if not, warn). if (const ObjCObjectPointerType *QIdTy = ReceiverType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { ObjCProtocolDecl *PDecl = *I; if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) break; // Since we aren't supporting "Class<foo>", look for a class method. if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) break; } } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). ClassDecl = OCIType->getInterfaceDecl(); // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). // The idea is to add class info to MethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); if (!Method) { // Search protocol qualifiers. for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), E = OCIType->qual_end(); QI != E; ++QI) { if ((Method = (*QI)->lookupInstanceMethod(Sel))) break; } } if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); if (!Method && (!Receiver || !isSelfExpr(Receiver))) { // If we still haven't found a method, look in the global pool. This // behavior isn't very desirable, however we need it for GCC // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; } } } if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && (ReceiverType->isPointerType() || ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) ImpCastExprToType(Receiver, Context.getObjCIdType(), CastExpr::CK_BitCast); else ImpCastExprToType(Receiver, Context.getObjCIdType(), CastExpr::CK_IntegralToPointer); ReceiverType = Receiver->getType(); } else if (getLangOptions().CPlusPlus && !PerformContextuallyConvertToObjCId(Receiver)) { if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { Receiver = ICE->getSubExpr(); ReceiverType = Receiver->getType(); } return BuildInstanceMessage(Owned(Receiver), ReceiverType, SuperLoc, Sel, Method, LBracLoc, RBracLoc, move(ArgsIn)); } else { // Reject other random receiver types (e.g. structs). Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); return ExprError(); } } } // Check the message arguments. unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); QualType ReturnType; if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false, LBracLoc, RBracLoc, ReturnType)) return ExprError(); if (!ReturnType->isVoidType()) { if (RequireCompleteType(LBracLoc, ReturnType, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); } // Construct the appropriate ObjCMessageExpr instance. Expr *Result; if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, ReceiverType, Sel, Method, Args, NumArgs, RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, Sel, Method, Args, NumArgs, RBracLoc); return MaybeBindToTemporary(Result); }
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; }
explicit Usage(const Expr *E) : E(E), IsArrow(false), Range(E->getSourceRange()) { }
bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, bool isClassMessage, SourceLocation lbrac, SourceLocation rbrac, QualType &ReturnType, ExprValueKind &VK) { if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). for (unsigned i = 0; i != NumArgs; i++) { if (Args[i]->isTypeDependent()) continue; DefaultArgumentPromotion(Args[i]); } unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; Diag(lbrac, DiagID) << Sel << isClassMessage << SourceRange(lbrac, rbrac); ReturnType = Context.getObjCIdType(); VK = VK_RValue; return false; } ReturnType = Method->getSendResultType(); VK = Expr::getValueKindForType(Method->getResultType()); unsigned NumNamedArgs = Sel.getNumArgs(); // Method might have more arguments than selector indicates. This is due // to addition of c-style arguments in method. if (Method->param_size() > Sel.getNumArgs()) NumNamedArgs = Method->param_size(); // FIXME. This need be cleaned up. if (NumArgs < NumNamedArgs) { Diag(lbrac, diag::err_typecheck_call_too_few_args) << 2 << NumNamedArgs << NumArgs; return false; } bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { // We can't do any type-checking on a type-dependent argument. if (Args[i]->isTypeDependent()) continue; Expr *argExpr = Args[i]; ParmVarDecl *Param = Method->param_begin()[i]; assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); if (RequireCompleteType(argExpr->getSourceRange().getBegin(), Param->getType(), PDiag(diag::err_call_incomplete_argument) << argExpr->getSourceRange())) return true; InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Param); ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr)); if (ArgE.isInvalid()) IsError = true; else Args[i] = ArgE.takeAs<Expr>(); } // Promote additional arguments to variadic methods. if (Method->isVariadic()) { for (unsigned i = NumNamedArgs; i < NumArgs; ++i) { if (Args[i]->isTypeDependent()) continue; IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); } } else { // Check for extra arguments to non-variadic methods. if (NumArgs != NumNamedArgs) { Diag(Args[NumNamedArgs]->getLocStart(), diag::err_typecheck_call_too_many_args) << 2 /*method*/ << NumNamedArgs << NumArgs << Method->getSourceRange() << SourceRange(Args[NumNamedArgs]->getLocStart(), Args[NumArgs-1]->getLocEnd()); } } DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs); return IsError; }