diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp | 938 |
1 files changed, 628 insertions, 310 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 0077d6c..d3d7d8b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -87,109 +87,6 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { } } -static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { - const auto *OMD = dyn_cast<ObjCMethodDecl>(D); - if (!OMD) - return false; - const ObjCInterfaceDecl *OID = OMD->getClassInterface(); - if (!OID) - return false; - - for (const ObjCCategoryDecl *Cat : OID->visible_categories()) - if (ObjCMethodDecl *CatMeth = - Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod())) - if (!CatMeth->hasAttr<AvailabilityAttr>()) - return true; - return false; -} - -AvailabilityResult -Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { - AvailabilityResult Result = D->getAvailability(Message); - - // For typedefs, if the typedef declaration appears available look - // to the underlying type to see if it is more restrictive. - while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { - if (Result == AR_Available) { - if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { - D = TT->getDecl(); - Result = D->getAvailability(Message); - continue; - } - } - break; - } - - // Forward class declarations get their attributes from their definition. - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { - if (IDecl->getDefinition()) { - D = IDecl->getDefinition(); - Result = D->getAvailability(Message); - } - } - - if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) - if (Result == AR_Available) { - const DeclContext *DC = ECD->getDeclContext(); - if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) - Result = TheEnumDecl->getAvailability(Message); - } - - if (Result == AR_NotYetIntroduced) { - // Don't do this for enums, they can't be redeclared. - if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) - return AR_Available; - - bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); - // Objective-C method declarations in categories are not modelled as - // redeclarations, so manually look for a redeclaration in a category - // if necessary. - if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) - Warn = false; - // In general, D will point to the most recent redeclaration. However, - // for `@class A;` decls, this isn't true -- manually go through the - // redecl chain in that case. - if (Warn && isa<ObjCInterfaceDecl>(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr<AvailabilityAttr>() || - Redecl->getAttr<AvailabilityAttr>()->isInherited()) - Warn = false; - - return Warn ? AR_NotYetIntroduced : AR_Available; - } - - return Result; -} - -static void -DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { - std::string Message; - // See if this declaration is unavailable, deprecated, or partial. - if (AvailabilityResult Result = - S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) { - - if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) { - S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; - return; - } - - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { - AvailabilityResult PDeclResult = PD->getAvailability(nullptr); - if (PDeclResult == Result) - ObjCPDecl = PD; - } - } - - S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass, - ObjCPDecl, ObjCPropertyAccess); - } -} - /// \brief Emit a note explaining that this function is deleted. void Sema::NoteDeletedFunction(FunctionDecl *Decl) { assert(Decl->isDeleted()); @@ -305,7 +202,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { /// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks) { if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -333,10 +231,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer) << D->getDeclName(); } else { - const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType(); - Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName() << (unsigned)AT->getKeyword(); + << D->getDeclName() << cast<VarDecl>(D)->getType(); } return true; } @@ -363,8 +259,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; + } - if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc)) + auto getReferencedObjCProp = [](const NamedDecl *D) -> + const ObjCPropertyDecl * { + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->findPropertyDecl(); + return nullptr; + }; + if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) { + if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc)) + return true; + } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) { return true; } @@ -381,8 +287,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } - DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, - ObjCPropertyAccess); + DiagnoseAvailabilityOfDecl(D, Loc, UnknownObjCClass, ObjCPropertyAccess, + AvoidPartialAvailabilityChecks); DiagnoseUnusedOfDecl(*this, D, Loc); @@ -706,8 +612,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // Loading a __weak object implicitly retains the value, so we need a cleanup to // balance that. - if (getLangOpts().ObjCAutoRefCount && - E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) + if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) Cleanup.setExprNeedsCleanups(true); ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E, @@ -1434,7 +1339,8 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // Decay and strip qualifiers for the controlling expression type, and handle // placeholder type replacement. See committee discussion from WG14 DR423. { - EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult R = DefaultFunctionArrayLvalueConversion(ControllingExpr); if (R.isInvalid()) return ExprError(); @@ -1443,7 +1349,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // The controlling expression is an unevaluated operand, so side effects are // likely unintended. - if (ActiveTemplateInstantiations.empty() && + if (!inTemplateInstantiation() && ControllingExpr->HasSideEffects(Context, false)) Diag(ControllingExpr->getExprLoc(), diag::warn_side_effects_unevaluated_context); @@ -1774,7 +1680,10 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart())) recordUseOfEvaluatedWeak(E); - if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + FieldDecl *FD = dyn_cast<FieldDecl>(D); + if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D)) + FD = IFD->getAnonField(); + if (FD) { UnusedPrivateFields.remove(FD); // Just in case we're building an illegal pointer-to-member. if (FD->isBitField()) @@ -1890,9 +1799,10 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // During a default argument instantiation the CurContext points // to a CXXMethodDecl; but we can't apply a this-> fixit inside a // function parameter list, hence add an explicit check. - bool isDefaultArgument = !ActiveTemplateInstantiations.empty() && - ActiveTemplateInstantiations.back().Kind == - ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation; + bool isDefaultArgument = + !CodeSynthesisContexts.empty() && + CodeSynthesisContexts.back().Kind == + CodeSynthesisContext::DefaultFunctionArgumentInstantiation; CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); bool isInstance = CurMethod && CurMethod->isInstance() && @@ -2127,6 +2037,12 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, IdentifierInfo *II = Name.getAsIdentifierInfo(); SourceLocation NameLoc = NameInfo.getLoc(); + if (II && II->isEditorPlaceholder()) { + // FIXME: When typed placeholders are supported we can create a typed + // placeholder expression node. + return ExprError(); + } + // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: // -- an identifier that was declared with a dependent type, @@ -2510,11 +2426,11 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, IV->getLocation(), SelfExpr.get(), true, true); + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) + recordUseOfEvaluatedWeak(Result); + } if (getLangOpts().ObjCAutoRefCount) { - if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { - if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) - recordUseOfEvaluatedWeak(Result); - } if (CurContext->isClosure()) Diag(Loc, diag::warn_implicitly_retains_self) << FixItHint::CreateInsertion(Loc, "self->"); @@ -3038,6 +2954,9 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } + case Decl::CXXDeductionGuide: + llvm_unreachable("building reference to deduction guide"); + case Decl::MSProperty: valueKind = VK_LValue; break; @@ -3694,7 +3613,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // The operand for sizeof and alignof is in an unevaluated expression context, // so side effects could result in unintended consequences. if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) && - ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, false)) + !inTemplateInstantiation() && E->HasSideEffects(Context, false)) Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), @@ -3969,7 +3888,8 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, T = cast<DecltypeType>(Ty)->desugar(); break; case Type::Auto: - T = cast<AutoType>(Ty)->getDeducedType(); + case Type::DeducedTemplateSpecialization: + T = cast<DeducedType>(Ty)->getDeducedType(); break; case Type::TypeOfExpr: T = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType(); @@ -4553,8 +4473,8 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, if (Param->hasUninstantiatedDefaultArg()) { Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); - EnterExpressionEvaluationContext EvalContext(*this, PotentiallyEvaluated, - Param); + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); // Instantiate the expression. MultiLevelTemplateArgumentList MutiLevelArgList @@ -5258,9 +5178,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); - // We aren't supposed to apply this logic for if there'Scope an '&' - // involved. + // We aren't supposed to apply this logic if there's an '&' involved. if (!find.HasFormOfMemberPointer) { + if (Expr::hasAnyTypeDependentArguments(ArgExprs)) + return new (Context) CallExpr( + Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl)) return BuildOverloadedCallExpr( @@ -5378,6 +5300,17 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, return ExprError(); } + // Interrupt handlers don't save off the VFP regs automatically on ARM, + // so there's some risk when calling out to non-interrupt handler functions + // that the callee might not preserve them. This is easy to diagnose here, + // but can be very challenging to debug. + if (auto *Caller = getCurFunctionDecl()) + if (Caller->hasAttr<ARMInterruptAttr>()) { + bool VFP = Context.getTargetInfo().hasFeature("vfp"); + if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())) + Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention); + } + // Promote the function operand. // We special-case function promotion here because we only allow promoting // builtin functions to function pointers in the callee of a call. @@ -6323,92 +6256,97 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, Qualifiers lhQual = lhptee.getQualifiers(); Qualifiers rhQual = rhptee.getQualifiers(); + unsigned ResultAddrSpace = 0; + unsigned LAddrSpace = lhQual.getAddressSpace(); + unsigned RAddrSpace = rhQual.getAddressSpace(); + if (S.getLangOpts().OpenCL) { + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + if (lhQual.isAddressSpaceSupersetOf(rhQual)) + ResultAddrSpace = LAddrSpace; + else if (rhQual.isAddressSpaceSupersetOf(lhQual)) + ResultAddrSpace = RAddrSpace; + else { + S.Diag(Loc, + diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) + << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + } + unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); + auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; lhQual.removeCVRQualifiers(); rhQual.removeCVRQualifiers(); + // OpenCL v2.0 specification doesn't extend compatibility of type qualifiers + // (C99 6.7.3) for address spaces. We assume that the check should behave in + // the same manner as it's defined for CVR qualifiers, so for OpenCL two + // qual types are compatible iff + // * corresponded types are compatible + // * CVR qualifiers are equal + // * address spaces are equal + // Thus for conditional operator we merge CVR and address space unqualified + // pointees and if there is a composite type we return a pointer to it with + // merged qualifiers. + if (S.getLangOpts().OpenCL) { + LHSCastKind = LAddrSpace == ResultAddrSpace + ? CK_BitCast + : CK_AddressSpaceConversion; + RHSCastKind = RAddrSpace == ResultAddrSpace + ? CK_BitCast + : CK_AddressSpaceConversion; + lhQual.removeAddressSpace(); + rhQual.removeAddressSpace(); + } + lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); - // For OpenCL: - // 1. If LHS and RHS types match exactly and: - // (a) AS match => use standard C rules, no bitcast or addrspacecast - // (b) AS overlap => generate addrspacecast - // (c) AS don't overlap => give an error - // 2. if LHS and RHS types don't match: - // (a) AS match => use standard C rules, generate bitcast - // (b) AS overlap => generate addrspacecast instead of bitcast - // (c) AS don't overlap => give an error - - // For OpenCL, non-null composite type is returned only for cases 1a and 1b. QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); - // OpenCL cases 1c, 2a, 2b, and 2c. if (CompositeTy.isNull()) { // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy; - if (S.getLangOpts().OpenCL) { - // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address - // spaces is disallowed. - unsigned ResultAddrSpace; - if (lhQual.isAddressSpaceSupersetOf(rhQual)) { - // Cases 2a and 2b. - ResultAddrSpace = lhQual.getAddressSpace(); - } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) { - // Cases 2a and 2b. - ResultAddrSpace = rhQual.getAddressSpace(); - } else { - // Cases 1c and 2c. - S.Diag(Loc, - diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) - << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - return QualType(); - } - - // Continue handling cases 2a and 2b. - incompatTy = S.Context.getPointerType( - S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); - LHS = S.ImpCastExprToType(LHS.get(), incompatTy, - (lhQual.getAddressSpace() != ResultAddrSpace) - ? CK_AddressSpaceConversion /* 2b */ - : CK_BitCast /* 2a */); - RHS = S.ImpCastExprToType(RHS.get(), incompatTy, - (rhQual.getAddressSpace() != ResultAddrSpace) - ? CK_AddressSpaceConversion /* 2b */ - : CK_BitCast /* 2a */); - } else { - S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - incompatTy = S.Context.getPointerType(S.Context.VoidTy); - LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast); - } + incompatTy = S.Context.getPointerType( + S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); + LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind); + RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind); + // FIXME: For OpenCL the warning emission and cast to void* leaves a room + // for casts between types with incompatible address space qualifiers. + // For the following code the compiler produces casts between global and + // local address spaces of the corresponded innermost pointees: + // local int *global *a; + // global int *global *b; + // a = (0 ? a : b); // see C99 6.5.16.1.p1. + S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); return incompatTy; } // The pointer types are compatible. - QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual); - auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; + // In case of OpenCL ResultTy should have the address space qualifier + // which is a superset of address spaces of both the 2nd and the 3rd + // operands of the conditional operator. + QualType ResultTy = [&, ResultAddrSpace]() { + if (S.getLangOpts().OpenCL) { + Qualifiers CompositeQuals = CompositeTy.getQualifiers(); + CompositeQuals.setAddressSpace(ResultAddrSpace); + return S.Context + .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals) + .withCVRQualifiers(MergedCVRQual); + } + return CompositeTy.withCVRQualifiers(MergedCVRQual); + }(); if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); - else { - // Cases 1a and 1b for OpenCL. - auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace(); - LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace - ? CK_BitCast /* 1a */ - : CK_AddressSpaceConversion /* 1b */; - RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace - ? CK_BitCast /* 1a */ - : CK_AddressSpaceConversion /* 1b */; + else ResultTy = S.Context.getPointerType(ResultTy); - } - // For case 1a of OpenCL, S.ImpCastExprToType will not insert bitcast - // if the target type does not change. LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); return ResultTy; @@ -7378,10 +7316,31 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType, Sema::AssignConvertType ConvTy = Sema::Compatible; // For blocks we enforce that qualifiers are identical. - if (lhptee.getLocalQualifiers() != rhptee.getLocalQualifiers()) + Qualifiers LQuals = lhptee.getLocalQualifiers(); + Qualifiers RQuals = rhptee.getLocalQualifiers(); + if (S.getLangOpts().OpenCL) { + LQuals.removeAddressSpace(); + RQuals.removeAddressSpace(); + } + if (LQuals != RQuals) ConvTy = Sema::CompatiblePointerDiscardsQualifiers; - if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) + // FIXME: OpenCL doesn't define the exact compile time semantics for a block + // assignment. + // The current behavior is similar to C++ lambdas. A block might be + // assigned to a variable iff its return type and parameters are compatible + // (C99 6.2.7) with the corresponding return type and parameters of the LHS of + // an assignment. Presumably it should behave in way that a function pointer + // assignment does in C, so for each parameter and return type: + // * CVR and address space of LHS should be a superset of CVR and address + // space of RHS. + // * unqualified types should be compatible. + if (S.getLangOpts().OpenCL) { + if (!S.Context.typesAreBlockPointerCompatible( + S.Context.getQualifiedType(LHSType.getUnqualifiedType(), LQuals), + S.Context.getQualifiedType(RHSType.getUnqualifiedType(), RQuals))) + return Sema::IncompatibleBlockPointer; + } else if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) return Sema::IncompatibleBlockPointer; return ConvTy; @@ -7603,7 +7562,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // U^ -> void* if (RHSType->getAs<BlockPointerType>()) { if (LHSPointer->getPointeeType()->isVoidType()) { - Kind = CK_BitCast; + unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); + unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); + Kind = + AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return Compatible; } } @@ -7615,7 +7579,13 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (isa<BlockPointerType>(LHSType)) { // U^ -> T^ if (RHSType->isBlockPointerType()) { - Kind = CK_BitCast; + unsigned AddrSpaceL = LHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); + unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); + Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -7648,7 +7618,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, Kind = CK_BitCast; Sema::AssignConvertType result = checkObjCPointerTypesForAssignment(*this, LHSType, RHSType); - if (getLangOpts().ObjCAutoRefCount && + if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && result == Compatible && !CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType)) result = IncompatibleObjCWeakRef; @@ -7855,7 +7825,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, if (RHS.isInvalid()) return Incompatible; Sema::AssignConvertType result = Compatible; - if (getLangOpts().ObjCAutoRefCount && + if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType)) result = IncompatibleObjCWeakRef; return result; @@ -7932,9 +7902,9 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, // Check for various Objective-C errors. If we are not reporting // diagnostics and just checking for errors, e.g., during overload // resolution, return Incompatible to indicate the failure. - if (getLangOpts().ObjCAutoRefCount && - CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, - Diagnose, DiagnoseCFAudited) != ACR_okay) { + if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && + CheckObjCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, + Diagnose, DiagnoseCFAudited) != ACR_okay) { if (!Diagnose) return Incompatible; } @@ -7964,34 +7934,71 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, return QualType(); } +// Diagnose cases where a scalar was implicitly converted to a vector and +// diagnose the underlying types. Otherwise, diagnose the error +// as invalid vector logical operands for non-C++ cases. +QualType Sema::InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS) { + QualType LHSType = LHS.get()->IgnoreImpCasts()->getType(); + QualType RHSType = RHS.get()->IgnoreImpCasts()->getType(); + + bool LHSNatVec = LHSType->isVectorType(); + bool RHSNatVec = RHSType->isVectorType(); + + if (!(LHSNatVec && RHSNatVec)) { + Expr *Vector = LHSNatVec ? LHS.get() : RHS.get(); + Expr *NonVector = !LHSNatVec ? LHS.get() : RHS.get(); + Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict) + << 0 << Vector->getType() << NonVector->IgnoreImpCasts()->getType() + << Vector->getSourceRange(); + return QualType(); + } + + Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict) + << 1 << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + + return QualType(); +} + /// Try to convert a value of non-vector type to a vector type by converting /// the type to the element type of the vector and then performing a splat. /// If the language is OpenCL, we only use conversions that promote scalar /// rank; for C, Obj-C, and C++ we allow any real scalar conversion except /// for float->int. /// +/// OpenCL V2.0 6.2.6.p2: +/// An error shall occur if any scalar operand type has greater rank +/// than the type of the vector element. +/// /// \param scalar - if non-null, actually perform the conversions /// \return true if the operation fails (but without diagnosing the failure) static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, QualType scalarTy, QualType vectorEltTy, - QualType vectorTy) { + QualType vectorTy, + unsigned &DiagID) { // The conversion to apply to the scalar before splatting it, // if necessary. CastKind scalarCast = CK_Invalid; if (vectorEltTy->isIntegralType(S.Context)) { - if (!scalarTy->isIntegralType(S.Context)) + if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() || + (scalarTy->isIntegerType() && + S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0))) { + DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type; return true; - if (S.getLangOpts().OpenCL && - S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0) + } + if (!scalarTy->isIntegralType(S.Context)) return true; scalarCast = CK_IntegralCast; } else if (vectorEltTy->isRealFloatingType()) { if (scalarTy->isRealFloatingType()) { if (S.getLangOpts().OpenCL && - S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0) + S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0) { + DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type; return true; + } scalarCast = CK_FloatingCast; } else if (scalarTy->isIntegralType(S.Context)) @@ -8011,6 +8018,162 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, return false; } +/// Test if a (constant) integer Int can be casted to another integer type +/// IntTy without losing precision. +static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, + QualType OtherIntTy) { + QualType IntTy = Int->get()->getType().getUnqualifiedType(); + + // Reject cases where the value of the Int is unknown as that would + // possibly cause truncation, but accept cases where the scalar can be + // demoted without loss of precision. + llvm::APSInt Result; + bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context); + int Order = S.Context.getIntegerTypeOrder(OtherIntTy, IntTy); + bool IntSigned = IntTy->hasSignedIntegerRepresentation(); + bool OtherIntSigned = OtherIntTy->hasSignedIntegerRepresentation(); + + if (CstInt) { + // If the scalar is constant and is of a higher order and has more active + // bits that the vector element type, reject it. + unsigned NumBits = IntSigned + ? (Result.isNegative() ? Result.getMinSignedBits() + : Result.getActiveBits()) + : Result.getActiveBits(); + if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits) + return true; + + // If the signedness of the scalar type and the vector element type + // differs and the number of bits is greater than that of the vector + // element reject it. + return (IntSigned != OtherIntSigned && + NumBits > S.Context.getIntWidth(OtherIntTy)); + } + + // Reject cases where the value of the scalar is not constant and it's + // order is greater than that of the vector element type. + return (Order < 0); +} + +/// Test if a (constant) integer Int can be casted to floating point type +/// FloatTy without losing precision. +static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int, + QualType FloatTy) { + QualType IntTy = Int->get()->getType().getUnqualifiedType(); + + // Determine if the integer constant can be expressed as a floating point + // number of the appropiate type. + llvm::APSInt Result; + bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context); + uint64_t Bits = 0; + if (CstInt) { + // Reject constants that would be truncated if they were converted to + // the floating point type. Test by simple to/from conversion. + // FIXME: Ideally the conversion to an APFloat and from an APFloat + // could be avoided if there was a convertFromAPInt method + // which could signal back if implicit truncation occurred. + llvm::APFloat Float(S.Context.getFloatTypeSemantics(FloatTy)); + Float.convertFromAPInt(Result, IntTy->hasSignedIntegerRepresentation(), + llvm::APFloat::rmTowardZero); + llvm::APSInt ConvertBack(S.Context.getIntWidth(IntTy), + !IntTy->hasSignedIntegerRepresentation()); + bool Ignored = false; + Float.convertToInteger(ConvertBack, llvm::APFloat::rmNearestTiesToEven, + &Ignored); + if (Result != ConvertBack) + return true; + } else { + // Reject types that cannot be fully encoded into the mantissa of + // the float. + Bits = S.Context.getTypeSize(IntTy); + unsigned FloatPrec = llvm::APFloat::semanticsPrecision( + S.Context.getFloatTypeSemantics(FloatTy)); + if (Bits > FloatPrec) + return true; + } + + return false; +} + +/// Attempt to convert and splat Scalar into a vector whose types matches +/// Vector following GCC conversion rules. The rule is that implicit +/// conversion can occur when Scalar can be casted to match Vector's element +/// type without causing truncation of Scalar. +static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, + ExprResult *Vector) { + QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType(); + QualType VectorTy = Vector->get()->getType().getUnqualifiedType(); + const VectorType *VT = VectorTy->getAs<VectorType>(); + + assert(!isa<ExtVectorType>(VT) && + "ExtVectorTypes should not be handled here!"); + + QualType VectorEltTy = VT->getElementType(); + + // Reject cases where the vector element type or the scalar element type are + // not integral or floating point types. + if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType()) + return true; + + // The conversion to apply to the scalar before splatting it, + // if necessary. + CastKind ScalarCast = CK_NoOp; + + // Accept cases where the vector elements are integers and the scalar is + // an integer. + // FIXME: Notionally if the scalar was a floating point value with a precise + // integral representation, we could cast it to an appropriate integer + // type and then perform the rest of the checks here. GCC will perform + // this conversion in some cases as determined by the input language. + // We should accept it on a language independent basis. + if (VectorEltTy->isIntegralType(S.Context) && + ScalarTy->isIntegralType(S.Context) && + S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy)) { + + if (canConvertIntToOtherIntTy(S, Scalar, VectorEltTy)) + return true; + + ScalarCast = CK_IntegralCast; + } else if (VectorEltTy->isRealFloatingType()) { + if (ScalarTy->isRealFloatingType()) { + + // Reject cases where the scalar type is not a constant and has a higher + // Order than the vector element type. + llvm::APFloat Result(0.0); + bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context); + int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy); + if (!CstScalar && Order < 0) + return true; + + // If the scalar cannot be safely casted to the vector element type, + // reject it. + if (CstScalar) { + bool Truncated = false; + Result.convert(S.Context.getFloatTypeSemantics(VectorEltTy), + llvm::APFloat::rmNearestTiesToEven, &Truncated); + if (Truncated) + return true; + } + + ScalarCast = CK_FloatingCast; + } else if (ScalarTy->isIntegralType(S.Context)) { + if (canConvertIntTyToFloatTy(S, Scalar, VectorEltTy)) + return true; + + ScalarCast = CK_IntegralToFloating; + } else + return true; + } + + // Adjust scalar if desired. + if (Scalar) { + if (ScalarCast != CK_NoOp) + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); + } + return false; +} + QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, @@ -8079,22 +8242,34 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, } } - // If there's an ext-vector type and a scalar, try to convert the scalar to + // If there's a vector type and a scalar, try to convert the scalar to // the vector element type and splat. - // FIXME: this should also work for regular vector types as supported in GCC. - if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) { - if (!tryVectorConvertAndSplat(*this, &RHS, RHSType, - LHSVecType->getElementType(), LHSType)) - return LHSType; + unsigned DiagID = diag::err_typecheck_vector_not_convertable; + if (!RHSVecType) { + if (isa<ExtVectorType>(LHSVecType)) { + if (!tryVectorConvertAndSplat(*this, &RHS, RHSType, + LHSVecType->getElementType(), LHSType, + DiagID)) + return LHSType; + } else { + if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS)) + return LHSType; + } } - if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) { - if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS), - LHSType, RHSVecType->getElementType(), - RHSType)) - return RHSType; + if (!LHSVecType) { + if (isa<ExtVectorType>(RHSVecType)) { + if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS), + LHSType, RHSVecType->getElementType(), + RHSType, DiagID)) + return RHSType; + } else { + if (LHS.get()->getValueKind() == VK_LValue || + !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS)) + return RHSType; + } } - // FIXME: The code below also handles convertion between vectors and + // FIXME: The code below also handles conversion between vectors and // non-scalars, we should break this down into fine grained specific checks // and emit proper diagnostics. QualType VecType = LHSVecType ? LHSType : RHSType; @@ -8113,7 +8288,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, // type. Note that this is already done by non-compound assignments in // CheckAssignmentConstraints. If it's a scalar type, only bitcast for // <1 x T> -> T. The result is also a vector type. - } else if (OtherType->isExtVectorType() || + } else if (OtherType->isExtVectorType() || OtherType->isVectorType() || (OtherType->isScalarType() && VT->getNumElements() == 1)) { ExprResult *RHSExpr = &RHS; *RHSExpr = ImpCastExprToType(RHSExpr->get(), LHSType, CK_BitCast); @@ -8144,8 +8319,24 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, return QualType(); } + + // If there is a vector type that is not a ExtVector and a scalar, we reach + // this point if scalar could not be converted to the vector's element type + // without truncation. + if ((RHSVecType && !isa<ExtVectorType>(RHSVecType)) || + (LHSVecType && !isa<ExtVectorType>(LHSVecType))) { + QualType Scalar = LHSVecType ? RHSType : LHSType; + QualType Vector = LHSVecType ? LHSType : RHSType; + unsigned ScalarOrVector = LHSVecType && RHSVecType ? 1 : 0; + Diag(Loc, + diag::err_typecheck_vector_not_convertable_implict_truncation) + << ScalarOrVector << Scalar << Vector; + + return QualType(); + } + // Otherwise, use the generic diagnostic. - Diag(Loc, diag::err_typecheck_vector_not_convertable) + Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); @@ -9231,7 +9422,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, !(LHSType->isBlockPointerType() && IsRelational) && !LHS.get()->getLocStart().isMacroID() && !RHS.get()->getLocStart().isMacroID() && - ActiveTemplateInstantiations.empty()) { + !inTemplateInstantiation()) { // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. @@ -9374,7 +9565,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // If both operands are pointers, [...] bring them to their composite // pointer type. if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >= - (IsRelational ? 2 : 1)) { + (IsRelational ? 2 : 1) && + (!LangOpts.ObjCAutoRefCount || + !(LHSType->isObjCObjectPointerType() || + RHSType->isObjCObjectPointerType()))) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); else @@ -9560,16 +9754,17 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (LHSIsNull && !RHSIsNull) { Expr *E = LHS.get(); if (getLangOpts().ObjCAutoRefCount) - CheckObjCARCConversion(SourceRange(), RHSType, E, CCK_ImplicitConversion); + CheckObjCConversion(SourceRange(), RHSType, E, + CCK_ImplicitConversion); LHS = ImpCastExprToType(E, RHSType, RPT ? CK_BitCast :CK_CPointerToObjCPointerCast); } else { Expr *E = RHS.get(); if (getLangOpts().ObjCAutoRefCount) - CheckObjCARCConversion(SourceRange(), LHSType, E, - CCK_ImplicitConversion, /*Diagnose=*/true, - /*DiagnoseCFAudited=*/false, Opc); + CheckObjCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion, + /*Diagnose=*/true, + /*DiagnoseCFAudited=*/false, Opc); RHS = ImpCastExprToType(E, LHSType, LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); } @@ -9657,24 +9852,45 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return InvalidOperands(Loc, LHS, RHS); } - -// Return a signed type that is of identical size and number of elements. -// For floating point vectors, return an integer type of identical size -// and number of elements. +// Return a signed ext_vector_type that is of identical size and number of +// elements. For floating point vectors, return an integer type of identical +// size and number of elements. In the non ext_vector_type case, search from +// the largest type to the smallest type to avoid cases where long long == long, +// where long gets picked over long long. QualType Sema::GetSignedVectorType(QualType V) { const VectorType *VTy = V->getAs<VectorType>(); unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); - if (TypeSize == Context.getTypeSize(Context.CharTy)) - return Context.getExtVectorType(Context.CharTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.ShortTy)) - return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.IntTy)) - return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); + + if (isa<ExtVectorType>(VTy)) { + if (TypeSize == Context.getTypeSize(Context.CharTy)) + return Context.getExtVectorType(Context.CharTy, VTy->getNumElements()); + else if (TypeSize == Context.getTypeSize(Context.ShortTy)) + return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements()); + else if (TypeSize == Context.getTypeSize(Context.IntTy)) + return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); + else if (TypeSize == Context.getTypeSize(Context.LongTy)) + return Context.getExtVectorType(Context.LongTy, VTy->getNumElements()); + assert(TypeSize == Context.getTypeSize(Context.LongLongTy) && + "Unhandled vector element size in vector compare"); + return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); + } + + if (TypeSize == Context.getTypeSize(Context.LongLongTy)) + return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(), + VectorType::GenericVector); else if (TypeSize == Context.getTypeSize(Context.LongTy)) - return Context.getExtVectorType(Context.LongTy, VTy->getNumElements()); - assert(TypeSize == Context.getTypeSize(Context.LongLongTy) && + return Context.getVectorType(Context.LongTy, VTy->getNumElements(), + VectorType::GenericVector); + else if (TypeSize == Context.getTypeSize(Context.IntTy)) + return Context.getVectorType(Context.IntTy, VTy->getNumElements(), + VectorType::GenericVector); + else if (TypeSize == Context.getTypeSize(Context.ShortTy)) + return Context.getVectorType(Context.ShortTy, VTy->getNumElements(), + VectorType::GenericVector); + assert(TypeSize == Context.getTypeSize(Context.CharTy) && "Unhandled vector element size in vector compare"); - return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); + return Context.getVectorType(Context.CharTy, VTy->getNumElements(), + VectorType::GenericVector); } /// CheckVectorCompareOperands - vector comparisons are a clang extension that @@ -9703,8 +9919,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. - if (!LHSType->hasFloatingRepresentation() && - ActiveTemplateInstantiations.empty()) { + if (!LHSType->hasFloatingRepresentation() && !inTemplateInstantiation()) { if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts())) if (DeclRefExpr* DRR @@ -9722,7 +9937,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, assert (RHS.get()->getType()->hasFloatingRepresentation()); CheckFloatComparison(Loc, LHS.get(), RHS.get()); } - + // Return a signed type for the vector. return GetSignedVectorType(vType); } @@ -9739,7 +9954,13 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && vType->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); - + // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the + // usage of the logical operators && and || with vectors in C. This + // check could be notionally dropped. + if (!getLangOpts().CPlusPlus && + !(isa<ExtVectorType>(vType->getAs<VectorType>()))) + return InvalidLogicalVectorOperands(Loc, LHS, RHS); + return GetSignedVectorType(LHS.get()->getType()); } @@ -9792,7 +10013,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, !LHS.get()->getType()->isBooleanType() && RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && // Don't warn in macros or template instantiations. - !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) { + !Loc.isMacroID() && !inTemplateInstantiation()) { // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. @@ -10268,7 +10489,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InnerLHS); if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>()) checkRetainCycles(LHSExpr, RHS.get()); + } + if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong || + LHSType.isNonWeakInMRRWithObjCWeak(Context)) { // It is safe to assign a weak reference into a strong variable. // Although this code can still have problems: // id x = self.weakProp; @@ -10276,11 +10500,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, // we do not warn to warn spuriously when 'x' and 'y' are on separate // paths through the function. This should be revisited if // -Wrepeated-use-of-weak is made flow-sensitive. + // For ObjCWeak only, we do not warn if the assign is to a non-weak + // variable, which will be valid for the current autorelease scope. if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, RHS.get()->getLocStart())) getCurFunction()->markSafeWeakUse(RHS.get()); - } else if (getLangOpts().ObjCAutoRefCount) { + } else if (getLangOpts().ObjCAutoRefCount || getLangOpts().ObjCWeak) { checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); } } @@ -10328,7 +10554,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { return; // Don't warn in template instantiations. - if (!ActiveTemplateInstantiations.empty()) + if (inTemplateInstantiation()) return; // Scope isn't fine-grained enough to whitelist the specific cases, so @@ -10923,7 +11149,7 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( /// suppressed in the event of macro expansions. static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, SourceLocation OpLoc) { - if (!S.ActiveTemplateInstantiations.empty()) + if (S.inTemplateInstantiation()) return; if (OpLoc.isInvalid() || OpLoc.isMacroID()) return; @@ -11063,7 +11289,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (LHSTy->isAtomicType() || RHSTy->isAtomicType()) { SourceRange SR(LHSExpr->getLocStart(), RHSExpr->getLocEnd()); if (BO_Assign == Opc) - Diag(OpLoc, diag::err_atomic_init_constant) << SR; + Diag(OpLoc, diag::err_opencl_atomic_init) << 0 << SR; else ResultTy = InvalidOperands(OpLoc, LHS, RHS); return ExprError(); @@ -11129,6 +11355,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); + LLVM_FALLTHROUGH; case BO_Xor: case BO_Or: ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); @@ -11171,6 +11398,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_AndAssign: case BO_OrAssign: // fallthrough DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); + LLVM_FALLTHROUGH; case BO_XorAssign: CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); CompLHSTy = CompResultTy; @@ -11212,7 +11440,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (CompResultTy.isNull()) return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, - OK, OpLoc, FPFeatures.fp_contract); + OK, OpLoc, FPFeatures); if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; @@ -11220,7 +11448,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } return new (Context) CompoundAssignOperator( LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, - OpLoc, FPFeatures.fp_contract); + OpLoc, FPFeatures); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -11493,6 +11721,28 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, RHSExpr->getType()->isOverloadableType()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } + + // If we're instantiating "a.x < b" or "A::x < b" and 'x' names a function + // template, diagnose the missing 'template' keyword instead of diagnosing + // an invalid use of a bound member function. + // + // Note that "A::x < b" might be valid if 'b' has an overloadable type due + // to C++1z [over.over]/1.4, but we already checked for that case above. + if (Opc == BO_LT && inTemplateInstantiation() && + (pty->getKind() == BuiltinType::BoundMember || + pty->getKind() == BuiltinType::Overload)) { + auto *OE = dyn_cast<OverloadExpr>(LHSExpr); + if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() && + std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) { + return isa<FunctionTemplateDecl>(ND); + })) { + Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc() + : OE->getNameLoc(), + diag::err_template_kw_missing) + << OE->getName().getAsString() << ""; + return ExprError(); + } + } ExprResult LHS = CheckPlaceholderExpr(LHSExpr); if (LHS.isInvalid()) return ExprError(); @@ -11618,16 +11868,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, << resultType << Input.get()->getSourceRange(); else if (resultType->hasIntegerRepresentation()) break; - else if (resultType->isExtVectorType()) { - if (Context.getLangOpts().OpenCL) { - // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate - // on vector float types. - QualType T = resultType->getAs<ExtVectorType>()->getElementType(); - if (!T->isIntegerType()) - return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) - << resultType << Input.get()->getSourceRange()); - } - break; + else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) { + // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate + // on vector float types. + QualType T = resultType->getAs<ExtVectorType>()->getElementType(); + if (!T->isIntegerType()) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); @@ -11659,7 +11906,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Context.getLangOpts().OpenCLVersion < 120) { // OpenCL v1.1 6.3.h: The logical operator not (!) does not // operate on scalar float types. - if (!resultType->isIntegerType()) + if (!resultType->isIntegerType() && !resultType->isPointerType()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } @@ -11677,6 +11924,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = GetSignedVectorType(resultType); break; } else { + // FIXME: GCC's vector extension permits the usage of '!' with a vector + // type in C++. We should allow that here too. return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } @@ -11701,11 +11950,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } break; case UO_Extension: - case UO_Coawait: resultType = Input.get()->getType(); VK = Input.get()->getValueKind(); OK = Input.get()->getObjectKind(); break; + case UO_Coawait: + // It's unnessesary to represent the pass-through operator co_await in the + // AST; just return the input expression instead. + assert(!Input.get()->getType()->isDependentType() && + "the co_await expression must be non-dependant before " + "building operator co_await"); + return Input; } if (resultType.isNull() || Input.isInvalid()) return ExprError(); @@ -12193,7 +12448,8 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { // Enter a new evaluation context to insulate the block from any // cleanups from the enclosing full-expression. - PushExpressionEvaluationContext(PotentiallyEvaluated); + PushExpressionEvaluationContext( + ExpressionEvaluationContext::PotentiallyEvaluated); } void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, @@ -12409,6 +12665,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BSI->TheDecl->setBody(cast<CompoundStmt>(Body)); + if (Body && getCurFunction()->HasPotentialAvailabilityViolations) + DiagnoseUnguardedAvailabilityViolations(BSI->TheDecl); + // Try to apply the named return value optimization. We have to check again // if we can do this, though, because blocks keep return statements around // to deduce an implicit return type. @@ -13086,7 +13345,7 @@ void Sema::PopExpressionEvaluationContext() { unsigned NumTypos = Rec.NumTypos; if (!Rec.Lambdas.empty()) { - if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { + if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) { unsigned D; if (Rec.isUnevaluated()) { // C++11 [expr.prim.lambda]p2: @@ -13107,7 +13366,7 @@ void Sema::PopExpressionEvaluationContext() { // are part of function-signatures. Be mindful that P0315 (Lambdas in // unevaluated contexts) might lift some of these restrictions in a // future version. - if (Rec.Context != ConstantEvaluated || !getLangOpts().CPlusPlus1z) + if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus1z) for (const auto *L : Rec.Lambdas) Diag(L->getLocStart(), D); } else { @@ -13124,7 +13383,7 @@ void Sema::PopExpressionEvaluationContext() { // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they // will never be constructed. - if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { + if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) { ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects, ExprCleanupObjects.end()); Cleanup = Rec.ParentCleanup; @@ -13166,19 +13425,19 @@ ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) { /// captured by C++'s idea of an "unevaluated context". static bool isEvaluatableContext(Sema &SemaRef) { switch (SemaRef.ExprEvalContexts.back().Context) { - case Sema::Unevaluated: - case Sema::UnevaluatedAbstract: - case Sema::DiscardedStatement: + case Sema::ExpressionEvaluationContext::Unevaluated: + case Sema::ExpressionEvaluationContext::UnevaluatedAbstract: + case Sema::ExpressionEvaluationContext::DiscardedStatement: // Expressions in this context are never evaluated. return false; - case Sema::UnevaluatedList: - case Sema::ConstantEvaluated: - case Sema::PotentiallyEvaluated: + case Sema::ExpressionEvaluationContext::UnevaluatedList: + case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: // Expressions in this context could be evaluated. return true; - case Sema::PotentiallyEvaluatedIfUsed: + case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: // Referenced declarations will only be used if the construct in the // containing expression is used, at which point we'll be given another // turn to mark them. @@ -13196,17 +13455,17 @@ static bool isOdrUseContext(Sema &SemaRef, bool SkipDependentUses = true) { return false; switch (SemaRef.ExprEvalContexts.back().Context) { - case Sema::Unevaluated: - case Sema::UnevaluatedList: - case Sema::UnevaluatedAbstract: - case Sema::DiscardedStatement: + case Sema::ExpressionEvaluationContext::Unevaluated: + case Sema::ExpressionEvaluationContext::UnevaluatedList: + case Sema::ExpressionEvaluationContext::UnevaluatedAbstract: + case Sema::ExpressionEvaluationContext::DiscardedStatement: return false; - case Sema::ConstantEvaluated: - case Sema::PotentiallyEvaluated: + case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: return true; - case Sema::PotentiallyEvaluatedIfUsed: + case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: return false; } llvm_unreachable("Invalid context"); @@ -13357,7 +13616,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (!AlreadyInstantiated || Func->isConstexpr()) { if (isa<CXXRecordDecl>(Func->getDeclContext()) && cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() && - ActiveTemplateInstantiations.size()) + CodeSynthesisContexts.size()) PendingLocalImplicitInstantiations.push_back( std::make_pair(Func, PointOfInstantiation)); else if (Func->isConstexpr()) @@ -13366,6 +13625,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // call to such a function. InstantiateFunctionDefinition(PointOfInstantiation, Func); else { + Func->setInstantiationIsPending(true); PendingInstantiations.push_back(std::make_pair(Func, PointOfInstantiation)); // Notify the consumer that a function was implicitly instantiated. @@ -13540,6 +13800,13 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, } return false; } + // OpenCL v2.0 s6.12.5: Blocks cannot reference/capture other blocks + if (S.getLangOpts().OpenCL && IsBlock && + Var->getType()->isBlockPointerType()) { + if (Diagnose) + S.Diag(Loc, diag::err_opencl_block_ref_block); + return false; + } return true; } @@ -13577,16 +13844,55 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, } // Warn about implicitly autoreleasing indirect parameters captured by blocks. - if (auto *PT = dyn_cast<PointerType>(CaptureType)) { + if (const auto *PT = CaptureType->getAs<PointerType>()) { + // This function finds out whether there is an AttributedType of kind + // attr_objc_ownership in Ty. The existence of AttributedType of kind + // attr_objc_ownership implies __autoreleasing was explicitly specified + // rather than being added implicitly by the compiler. + auto IsObjCOwnershipAttributedType = [](QualType Ty) { + while (const auto *AttrTy = Ty->getAs<AttributedType>()) { + if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership) + return true; + + // Peel off AttributedTypes that are not of kind objc_ownership. + Ty = AttrTy->getModifiedType(); + } + + return false; + }; + QualType PointeeTy = PT->getPointeeType(); - if (isa<ObjCObjectPointerType>(PointeeTy.getCanonicalType()) && + + if (PointeeTy->getAs<ObjCObjectPointerType>() && PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing && - !isa<AttributedType>(PointeeTy)) { + !IsObjCOwnershipAttributedType(PointeeTy)) { if (BuildAndDiagnose) { SourceLocation VarLoc = Var->getLocation(); S.Diag(Loc, diag::warn_block_capture_autoreleasing); - S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing) << - FixItHint::CreateInsertion(VarLoc, "__autoreleasing"); + { + auto AddAutoreleaseNote = + S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing); + // Provide a fix-it for the '__autoreleasing' keyword at the + // appropriate location in the variable's type. + if (const auto *TSI = Var->getTypeSourceInfo()) { + PointerTypeLoc PTL = + TSI->getTypeLoc().getAsAdjusted<PointerTypeLoc>(); + if (PTL) { + SourceLocation Loc = PTL.getPointeeLoc().getEndLoc(); + Loc = Lexer::getLocForEndOfToken(Loc, 0, S.getSourceManager(), + S.getLangOpts()); + if (Loc.isValid()) { + StringRef CharAtLoc = Lexer::getSourceText( + CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(1)), + S.getSourceManager(), S.getLangOpts()); + AddAutoreleaseNote << FixItHint::CreateInsertion( + Loc, CharAtLoc.empty() || !isWhitespace(CharAtLoc[0]) + ? " __autoreleasing " + : " __autoreleasing"); + } + } + } + } S.Diag(VarLoc, diag::note_declare_parameter_strong); } } @@ -13615,7 +13921,8 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, // Enter a new evaluation context to insulate the copy // full-expression. - EnterExpressionEvaluationContext scope(S, S.PotentiallyEvaluated); + EnterExpressionEvaluationContext scope( + S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); // According to the blocks spec, the capture of a variable from // the stack requires a const copy constructor. This is not true @@ -13898,8 +14205,10 @@ bool Sema::tryCaptureVariable( // Check whether we've already captured it. if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, - DeclRefType)) + DeclRefType)) { + CSI->getCapture(Var).markUsed(BuildAndDiagnose); break; + } // If we are instantiating a generic lambda call operator body, // we do not want to capture new variables. What was captured // during either a lambdas transformation or initial parsing @@ -14227,8 +14536,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, (SemaRef.CurContext != Var->getDeclContext() && Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); if (RefersToEnclosingScope) { - if (LambdaScopeInfo *const LSI = - SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) { + LambdaScopeInfo *const LSI = + SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); + if (LSI && !LSI->CallOperator->Encloses(Var->getDeclContext())) { // If a variable could potentially be odr-used, defer marking it so // until we finish analyzing the full expression for any // lvalue-to-rvalue @@ -14278,24 +14588,24 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, ME->performsVirtualDispatch(SemaRef.getLangOpts()); if (!IsVirtualCall) return; - const Expr *Base = ME->getBase(); - const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); - if (!MostDerivedClassDecl) - return; - CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl); - if (!DM || DM->isPure()) - return; - SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); + + // If it's possible to devirtualize the call, mark the called function + // referenced. + CXXMethodDecl *DM = MD->getDevirtualizedMethod( + ME->getBase(), SemaRef.getLangOpts().AppleKext); + if (DM) + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. -void Sema::MarkDeclRefReferenced(DeclRefExpr *E) { +void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even // if it's a qualified reference. bool OdrUse = true; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) - if (Method->isVirtual()) + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) + if (Method->isVirtual() && + !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } @@ -14363,7 +14673,8 @@ bool MarkReferencedDecls::TraverseTemplateArgument( const TemplateArgument &Arg) { { // A non-type template argument is a constant-evaluated context. - EnterExpressionEvaluationContext Evaluated(S, Sema::ConstantEvaluated); + EnterExpressionEvaluationContext Evaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (Arg.getKind() == TemplateArgument::Declaration) { if (Decl *D = Arg.getAsDecl()) S.MarkAnyDeclReferenced(Loc, D, true); @@ -14483,19 +14794,19 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E, bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { - case Unevaluated: - case UnevaluatedList: - case UnevaluatedAbstract: - case DiscardedStatement: + case ExpressionEvaluationContext::Unevaluated: + case ExpressionEvaluationContext::UnevaluatedList: + case ExpressionEvaluationContext::UnevaluatedAbstract: + case ExpressionEvaluationContext::DiscardedStatement: // The argument will never be evaluated, so don't complain. break; - case ConstantEvaluated: + case ExpressionEvaluationContext::ConstantEvaluated: // Relevant diagnostics should be produced by constant evaluation. break; - case PotentiallyEvaluated: - case PotentiallyEvaluatedIfUsed: + case ExpressionEvaluationContext::PotentiallyEvaluated: + case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: if (Statement && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); @@ -15226,7 +15537,7 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { } /// Check for operands with placeholder types and complain if found. -/// Returns true if there was an error and no recovery was possible. +/// Returns ExprError() if there was an error and no recovery was possible. ExprResult Sema::CheckPlaceholderExpr(Expr *E) { if (!getLangOpts().CPlusPlus) { // C cannot handle TypoExpr nodes on either side of a binop because it @@ -15374,6 +15685,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( if (Spec != AvailSpecs.end()) Version = Spec->getVersion(); + // The use of `@available` in the enclosing function should be analyzed to + // warn when it's used inappropriately (i.e. not if(@available)). + if (getCurFunctionOrMethodDecl()) + getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + else if (getCurBlock() || getCurLambda()) + getCurFunction()->HasPotentialAvailabilityViolations = true; + return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } |