bool shouldProceed(void *S, void *T) { using namespace clang; Sema *Sem = (Sema *)S; DiagnosticsEngine& Diag = Sem->getDiagnostics(); cling::Transaction* Trans = (cling::Transaction*)T; // Here we will cheat a bit and assume that the warning came from the last // stmt, which will be in the 90% of the cases. CompoundStmt* CS = cast<CompoundStmt>(Trans->getWrapperFD()->getBody()); // Skip the NullStmts. SourceLocation Loc = CS->getLocStart(); for(CompoundStmt::const_reverse_body_iterator I = CS->body_rbegin(), E = CS->body_rend(); I != E; ++I) if (!isa<NullStmt>(*I)) { Loc = (*I)->getLocStart(); break; } Diag.Report(Loc, diag::warn_null_ptr_deref); if (isatty(fileno(stdin))) { int input = getchar(); getchar(); if (input == 'y' || input == 'Y') return false; } return true; }
// Do we know that we will eventually codegen the given function? static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { // Templates are emitted when they're instantiated. if (FD->isDependentContext()) return false; // When compiling for device, host functions are never emitted. Similarly, // when compiling for host, device and global functions are never emitted. // (Technically, we do emit a host-side stub for global functions, but this // doesn't count for our purposes here.) Sema::CUDAFunctionTarget T = S.IdentifyCUDATarget(FD); if (S.getLangOpts().CUDAIsDevice && T == Sema::CFT_Host) return false; if (!S.getLangOpts().CUDAIsDevice && (T == Sema::CFT_Device || T == Sema::CFT_Global)) return false; // Check whether this function is externally visible -- if so, it's // known-emitted. // // We have to check the GVA linkage of the function's *definition* -- if we // only have a declaration, we don't know whether or not the function will be // emitted, because (say) the definition could include "inline". FunctionDecl *Def = FD->getDefinition(); if (Def && !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def))) return true; // Otherwise, the function is known-emitted if it's in our set of // known-emitted functions. return S.DeviceKnownEmittedFns.count(FD) > 0; }
/// Build a call to 'operator co_await' if there is a suitable operator for /// the given expression. static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S, SourceLocation Loc, Expr *E) { UnresolvedSet<16> Functions; SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(), Functions); return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E); }
bool VisitCompoundStmt(CompoundStmt* CS) { for(CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); I != E; ++I) { if (!isa<BinaryOperator>(*I)) continue; const BinaryOperator* BinOp = cast<BinaryOperator>(*I); if (isAutoCandidate(BinOp)) { ASTContext& C = m_Sema->getASTContext(); VarDecl* VD = cast<VarDecl>(cast<DeclRefExpr>(BinOp->getLHS())->getDecl()); TypeSourceInfo* ResTSI = 0; TypeSourceInfo* TrivialTSI = C.getTrivialTypeSourceInfo(VD->getType()); Expr* RHS = BinOp->getRHS(); m_Sema->DeduceAutoType(TrivialTSI, RHS, ResTSI); VD->setTypeSourceInfo(ResTSI); VD->setType(ResTSI->getType()); VD->setInit(RHS); Sema::DeclGroupPtrTy VDPtrTy = m_Sema->ConvertDeclToDeclGroup(VD); // Transform the AST into a "sane" state. Replace the binary operator // with decl stmt, because the binop semantically is a decl with init. StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy, BinOp->getLocStart(), BinOp->getLocEnd()); assert(!DS.isInvalid() && "Invalid DeclStmt."); *I = DS.take(); } } return true; // returning false will abort the in-depth traversal. }
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)); }
static bool isValidCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { // 'co_await' and 'co_yield' are not permitted in unevaluated operands. if (S.isUnevaluatedContext()) { S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; return false; } // Any other usage must be within a function. auto *FD = dyn_cast<FunctionDecl>(S.CurContext); if (!FD) { S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext) ? diag::err_coroutine_objc_method : diag::err_coroutine_outside_function) << Keyword; return false; } // An enumeration for mapping the diagnostic type to the correct diagnostic // selection index. enum InvalidFuncDiag { DiagCtor = 0, DiagDtor, DiagCopyAssign, DiagMoveAssign, DiagMain, DiagConstexpr, DiagAutoRet, DiagVarargs, }; bool Diagnosed = false; auto DiagInvalid = [&](InvalidFuncDiag ID) { S.Diag(Loc, diag::err_coroutine_invalid_func_context) << ID << Keyword; Diagnosed = true; return false; }; // Diagnose when a constructor, destructor, copy/move assignment operator, // or the function 'main' are declared as a coroutine. auto *MD = dyn_cast<CXXMethodDecl>(FD); if (MD && isa<CXXConstructorDecl>(MD)) return DiagInvalid(DiagCtor); else if (MD && isa<CXXDestructorDecl>(MD)) return DiagInvalid(DiagDtor); else if (MD && MD->isCopyAssignmentOperator()) return DiagInvalid(DiagCopyAssign); else if (MD && MD->isMoveAssignmentOperator()) return DiagInvalid(DiagMoveAssign); else if (FD->isMain()) return DiagInvalid(DiagMain); // Emit a diagnostics for each of the following conditions which is not met. if (FD->isConstexpr()) DiagInvalid(DiagConstexpr); if (FD->getReturnType()->isUndeducedType()) DiagInvalid(DiagAutoRet); if (FD->isVariadic()) DiagInvalid(DiagVarargs); return !Diagnosed; }
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Attribute can be applied only to functions or variables. FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (!FD && !isa<VarDecl>(D)) { // Apparently Visual C++ thinks it is okay to not emit a warning // in this case, so only emit a warning when -fms-extensions is not // specified. if (!S.getLangOpts().MicrosoftExt) S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } // Currently, the dllimport attribute is ignored for inlined functions. // Warning is emitted. if (FD && FD->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } unsigned Index = Attr.getAttributeSpellingListIndex(); DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index); if (NewAttr) D->addAttr(NewAttr); }
static void EraseUnwantedCUDAMatchesImpl(Sema &S, const FunctionDecl *Caller, llvm::SmallVectorImpl<T> &Matches, FetchDeclFn FetchDecl) { assert(S.getLangOpts().CUDATargetOverloads && "Should not be called w/o enabled target overloads."); if (Matches.size() <= 1) return; // Find the best call preference among the functions in Matches. Sema::CUDAFunctionPreference P, BestCFP = Sema::CFP_Never; for (auto const &Match : Matches) { P = S.IdentifyCUDAPreference(Caller, FetchDecl(Match)); if (P > BestCFP) BestCFP = P; } // Erase all functions with lower priority. for (unsigned I = 0, N = Matches.size(); I != N;) if (S.IdentifyCUDAPreference(Caller, FetchDecl(Matches[I])) < BestCFP) { Matches[I] = Matches[--N]; Matches.resize(N); } else { ++I; } }
static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType, SourceLocation Loc) { QualType CoroHandleType = lookupCoroutineHandleType(S, PromiseType, Loc); if (CoroHandleType.isNull()) return ExprError(); DeclContext *LookupCtx = S.computeDeclContext(CoroHandleType); LookupResult Found(S, &S.PP.getIdentifierTable().get("from_address"), Loc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Found, LookupCtx)) { S.Diag(Loc, diag::err_coroutine_handle_missing_member) << "from_address"; return ExprError(); } Expr *FramePtr = buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {}); CXXScopeSpec SS; ExprResult FromAddr = S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false); if (FromAddr.isInvalid()) return ExprError(); return S.ActOnCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc); }
static void HandleX86ForceAlignArgPointerAttr(Decl *D, const AttributeList& Attr, Sema &S) { // Check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } // If we try to apply it to a function pointer, don't warn, but don't // do anything, either. It doesn't matter anyway, because there's nothing // special about calling a force_align_arg_pointer function. ValueDecl *VD = dyn_cast<ValueDecl>(D); if (VD && VD->getType()->isFunctionPointerType()) return; // Also don't warn on function pointer typedefs. TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || TD->getUnderlyingType()->isFunctionType())) return; // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << /* function */0; return; } D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context)); }
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } // Attribute can be applied only to functions or variables. FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (!FD && !isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; if (FD && FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; } unsigned Index = Attr.getAttributeSpellingListIndex(); DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index); if (NewAttr) D->addAttr(NewAttr); }
static bool CheckNakedParmReference(Expr *E, Sema &S) { FunctionDecl *Func = dyn_cast<FunctionDecl>(S.CurContext); if (!Func) return false; if (!Func->hasAttr<NakedAttr>()) return false; SmallVector<Expr*, 4> WorkList; WorkList.push_back(E); while (WorkList.size()) { Expr *E = WorkList.pop_back_val(); if (isa<CXXThisExpr>(E)) { S.Diag(E->getLocStart(), diag::err_asm_naked_this_ref); S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); return true; } if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { if (isa<ParmVarDecl>(DRE->getDecl())) { S.Diag(DRE->getLocStart(), diag::err_asm_naked_parm_ref); S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); return true; } } for (Stmt *Child : E->children()) { if (Expr *E = dyn_cast_or_null<Expr>(Child)) WorkList.push_back(E); } } return false; }
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } // Attribute can be applied only to functions or variables. if (isa<VarDecl>(D)) { D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context)); return; } FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (!FD) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; if (FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; } D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context)); }
/// 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); }
/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the /// specified type. The attribute contains 1 argument, weak or strong. static void HandleObjCGCTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S) { if (Type.getObjCGCAttr() != QualType::GCNone) { S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); return; } // Check the attribute arguments. if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; return; } QualType::GCAttrTypes GCAttr; if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } if (Attr.getParameterName()->isStr("weak")) GCAttr = QualType::Weak; else if (Attr.getParameterName()->isStr("strong")) GCAttr = QualType::Strong; else { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "objc_gc" << Attr.getParameterName(); return; } Type = S.Context.getObjCGCQualType(Type, GCAttr); }
/// Tests whether a conversion according to N2844 is valid. TryStaticCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange) { // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". const RValueReferenceType *R = DestType->getAsRValueReferenceType(); if (!R) return TSC_NotApplicable; if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) return TSC_NotApplicable; // Because we try the reference downcast before this function, from now on // this is the only cast possibility, so we issue an error if we fail now. bool DerivedToBase; if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), DerivedToBase) < Sema::Ref_Compatible_With_Added_Qualification) { Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast) << SrcExpr->getType() << R->getPointeeType() << OpRange; return TSC_Failed; } // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation // than nothing. return TSC_Success; }
/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently /// ignore "noop" casts in places where an lvalue is required by an inline asm. /// We emulate this behavior when -fheinous-gnu-extensions is specified, but /// provide a strong guidance to not use it. /// /// This method checks to see if the argument is an acceptable l-value and /// returns false if it is a case we can handle. static bool CheckAsmLValue(const Expr *E, Sema &S) { // Type dependent expressions will be checked during instantiation. if (E->isTypeDependent()) return false; if (E->isLValue()) return false; // Cool, this is an lvalue. // Okay, this is not an lvalue, but perhaps it is the result of a cast that we // are supposed to allow. const Expr *E2 = E->IgnoreParenNoopCasts(S.Context); if (E != E2 && E2->isLValue()) { if (!S.getLangOpts().HeinousExtensions) S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) << E->getSourceRange(); else S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue) << E->getSourceRange(); // Accept, even if we emitted an error diagnostic. return false; } // None of the above, just randomly invalid non-lvalue. return true; }
static void HandleARMInterruptAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Check the attribute arguments. if (Attr.getNumArgs() > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; return; } StringRef Str; SourceLocation ArgLoc; if (Attr.getNumArgs() == 0) Str = ""; else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) return; ARMInterruptAttr::InterruptType Kind; if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << Attr.getName() << Str << ArgLoc; return; } unsigned Index = Attr.getAttributeSpellingListIndex(); d->addAttr(::new (S.Context) ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); }
bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy) { // OpenCL v1.1 s6.8g: "The extern, static, auto and register storage-class // specifiers are not supported. // It seems sensible to prohibit private_extern too // The cl_clang_storage_class_specifiers extension enables support for // these storage-class specifiers. // OpenCL v1.2 s6.8 changes this to "The auto and register storage-class // specifiers are not supported." if (S.getLangOpts().OpenCL && !S.getOpenCLOptions().cl_clang_storage_class_specifiers) { switch (SC) { case SCS_extern: case SCS_private_extern: case SCS_static: if (S.getLangOpts().OpenCLVersion < 120) { DiagID = diag::err_opencl_unknown_type_specifier; PrevSpec = getSpecifierName(SC); return true; } break; case SCS_auto: case SCS_register: DiagID = diag::err_opencl_unknown_type_specifier; PrevSpec = getSpecifierName(SC); return true; default: break; } } if (StorageClassSpec != SCS_unspecified) { // Maybe this is an attempt to use C++11 'auto' outside of C++11 mode. bool isInvalid = true; if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) { if (SC == SCS_auto) return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, Policy); if (StorageClassSpec == SCS_auto) { isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc, PrevSpec, DiagID, Policy); assert(!isInvalid && "auto SCS -> TST recovery failed"); } } // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and // the new storage class is 'typedef'. if (isInvalid && !(SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern && SC == SCS_typedef)) return BadSpecifier(SC, (SCS)StorageClassSpec, PrevSpec, DiagID); } StorageClassSpec = SC; StorageClassSpecLoc = Loc; assert((unsigned)SC == StorageClassSpec && "SCS constants overflow bitfield"); return false; }
/// Build calls to await_ready, await_suspend, and await_resume for a co_await /// expression. static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, SourceLocation Loc, Expr *E) { OpaqueValueExpr *Operand = new (S.Context) OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E); // Assume invalid until we see otherwise. ReadySuspendResumeResult Calls = {{}, Operand, /*IsInvalid=*/true}; ExprResult CoroHandleRes = buildCoroutineHandle(S, CoroPromise->getType(), Loc); if (CoroHandleRes.isInvalid()) return Calls; Expr *CoroHandle = CoroHandleRes.get(); const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"}; MultiExprArg Args[] = {None, CoroHandle, None}; for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) { ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], Args[I]); if (Result.isInvalid()) return Calls; Calls.Results[I] = Result.get(); } // Assume the calls are valid; all further checking should make them invalid. Calls.IsInvalid = false; using ACT = ReadySuspendResumeResult::AwaitCallType; CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]); if (!AwaitReady->getType()->isDependentType()) { // [expr.await]p3 [...] // — await-ready is the expression e.await_ready(), contextually converted // to bool. ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady); if (Conv.isInvalid()) { S.Diag(AwaitReady->getDirectCallee()->getLocStart(), diag::note_await_ready_no_bool_conversion); S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) << AwaitReady->getDirectCallee() << E->getSourceRange(); Calls.IsInvalid = true; } Calls.Results[ACT::ACT_Ready] = Conv.get(); } CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]); if (!AwaitSuspend->getType()->isDependentType()) { // [expr.await]p3 [...] // - await-suspend is the expression e.await_suspend(h), which shall be // a prvalue of type void or bool. QualType RetType = AwaitSuspend->getType(); if (RetType != S.Context.BoolTy && RetType != S.Context.VoidTy) { S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(), diag::err_await_suspend_invalid_return_type) << RetType; S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) << AwaitSuspend->getDirectCallee(); Calls.IsInvalid = true; } } return Calls; }
/// Produce primary diagnostic for an indirect jump statement. static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump, LabelDecl *Target, bool &Diagnosed) { if (Diagnosed) return; S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); Diagnosed = true; }
static ExprResult BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo) { // x.a is an l-value if 'a' has a reference type. Otherwise: // x.a is an l-value/x-value/pr-value if the base is (and note // that *x is always an l-value), except that if the base isn't // an ordinary object then we must have an rvalue. ExprValueKind VK = VK_LValue; ExprObjectKind OK = OK_Ordinary; if (!IsArrow) { if (BaseExpr->getObjectKind() == OK_Ordinary) VK = BaseExpr->getValueKind(); else VK = VK_RValue; } if (VK != VK_RValue && Field->isBitField()) OK = OK_BitField; // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] QualType MemberType = Field->getType(); if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) { MemberType = Ref->getPointeeType(); VK = VK_LValue; } else { QualType BaseType = BaseExpr->getType(); if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType(); Qualifiers BaseQuals = BaseType.getQualifiers(); // CVR attributes from the base are picked up by members, // except that 'mutable' members don't pick up 'const'. if (Field->isMutable()) BaseQuals.removeConst(); Qualifiers MemberQuals = S.Context.getCanonicalType(MemberType).getQualifiers(); assert(!MemberQuals.hasAddressSpace()); Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) MemberType = S.Context.getQualifiedType(MemberType, Combined); } S.UnusedPrivateFields.remove(Field); ExprResult Base = S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), FoundDecl, Field); if (Base.isInvalid()) return ExprError(); return S.Owned(BuildMemberExpr(S, S.Context, Base.take(), IsArrow, Field, FoundDecl, MemberNameInfo, MemberType, VK, OK)); }
void safe_printf(char *format,...) { va_list arglist; services_sema.Wait(); va_start(arglist,format); vprintf(format,arglist); va_end(arglist); services_sema.Post(); }
static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) { if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) { auto *MethodDecl = MbrRef->getMethodDecl(); S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here) << MethodDecl; } S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn.getFirstCoroutineStmtKeyword(); }
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an /// uninitialized variable. This manages the different forms of diagnostic /// emitted for particular types of uses. Returns true if the use was diagnosed /// as a warning. If a pariticular use is one we omit warnings for, returns /// false. static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, const Expr *E, bool isAlwaysUninit) { bool isSelfInit = false; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { if (isAlwaysUninit) { // Inspect the initializer of the variable declaration which is // being referenced prior to its initialization. We emit // specialized diagnostics for self-initialization, and we // specifically avoid warning about self references which take the // form of: // // int x = x; // // This is used to indicate to GCC that 'x' is intentionally left // uninitialized. Proven code paths which access 'x' in // an uninitialized state after this will still warn. // // TODO: Should we suppress maybe-uninitialized warnings for // variables initialized in this way? if (const Expr *Initializer = VD->getInit()) { if (DRE == Initializer->IgnoreParenImpCasts()) return false; ContainsReference CR(S.Context, DRE); CR.Visit(const_cast<Expr*>(Initializer)); isSelfInit = CR.doesContainReference(); } if (isSelfInit) { S.Diag(DRE->getLocStart(), diag::warn_uninit_self_reference_in_init) << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); } else { S.Diag(DRE->getLocStart(), diag::warn_uninit_var) << VD->getDeclName() << DRE->getSourceRange(); } } else { S.Diag(DRE->getLocStart(), diag::warn_maybe_uninit_var) << VD->getDeclName() << DRE->getSourceRange(); } } else { const BlockExpr *BE = cast<BlockExpr>(E); S.Diag(BE->getLocStart(), isAlwaysUninit ? diag::warn_uninit_var_captured_by_block : diag::warn_maybe_uninit_var_captured_by_block) << VD->getDeclName(); } // Report where the variable was declared when the use wasn't within // the initializer of that declaration. if (!isSelfInit) S.Diag(VD->getLocStart(), diag::note_uninit_var_def) << VD->getDeclName(); return true; }
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is /// valid. /// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code /// like this: /// char *bytes = reinterpret_cast\<char*\>(int_ptr); void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange) { if (!DestType->isLValueReferenceType()) Self.DefaultFunctionArrayConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret << SrcExpr->getType() << DestType << OpRange; }
/// TryStaticMemberPointerUpcast - Tests whether a conversion according to /// C++ 5.2.9p9 is valid: /// /// An rvalue of type "pointer to member of D of type cv1 T" can be /// converted to an rvalue of type "pointer to member of B of type cv2 T", /// where B is a base class of D [...]. /// TryStaticCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange) { const MemberPointerType *SrcMemPtr = SrcType->getAsMemberPointerType(); if (!SrcMemPtr) return TSC_NotApplicable; const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(); if (!DestMemPtr) return TSC_NotApplicable; // T == T, modulo cv if (Self.Context.getCanonicalType( SrcMemPtr->getPointeeType().getUnqualifiedType()) != Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). getUnqualifiedType())) return TSC_NotApplicable; // B base of D QualType SrcClass(SrcMemPtr->getClass(), 0); QualType DestClass(DestMemPtr->getClass(), 0); BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { return TSC_NotApplicable; } // B is a base of D. But is it an allowed base? If not, it's a hard error. if (Paths.isAmbiguous(DestClass)) { Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); assert(StillOkay); StillOkay = StillOkay; std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; return TSC_Failed; } if (const RecordType *VBase = Paths.getDetectedVirtual()) { Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual) << SrcClass << DestClass << QualType(VBase, 0) << OpRange; return TSC_Failed; } // FIXME: Test accessibility. return TSC_Success; }
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } unsigned Index = Attr.getAttributeSpellingListIndex(); DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index); if (NewAttr) D->addAttr(NewAttr); }
static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc, StringRef Keyword) { if (!checkCoroutineContext(S, KWLoc, Keyword)) return false; auto *ScopeInfo = S.getCurFunction(); assert(ScopeInfo->CoroutinePromise); // If we have existing coroutine statements then we have already built // the initial and final suspend points. if (!ScopeInfo->NeedsCoroutineSuspends) return true; ScopeInfo->setNeedsCoroutineSuspends(false); auto *Fn = cast<FunctionDecl>(S.CurContext); SourceLocation Loc = Fn->getLocation(); // Build the initial suspend point auto buildSuspends = [&](StringRef Name) mutable -> StmtResult { ExprResult Suspend = buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None); if (Suspend.isInvalid()) return StmtError(); Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get()); if (Suspend.isInvalid()) return StmtError(); Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(), /*IsImplicit*/ true); Suspend = S.ActOnFinishFullExpr(Suspend.get()); if (Suspend.isInvalid()) { S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required) << ((Name == "initial_suspend") ? 0 : 1); S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword; return StmtError(); } return cast<Stmt>(Suspend.get()); }; StmtResult InitSuspend = buildSuspends("initial_suspend"); if (InitSuspend.isInvalid()) return true; StmtResult FinalSuspend = buildSuspends("final_suspend"); if (FinalSuspend.isInvalid()) return true; ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get()); return true; }
static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc, StringRef Name, MultiExprArg Args) { DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc); // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&. CXXScopeSpec SS; ExprResult Result = S.BuildMemberReferenceExpr( Base, Base->getType(), Loc, /*IsPtr=*/false, SS, SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr, /*Scope=*/nullptr); if (Result.isInvalid()) return ExprError(); return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr); }