diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp | 856 |
1 files changed, 642 insertions, 214 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 8be1157..7ab269c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -76,25 +76,57 @@ bool Sema::CanUseDecl(NamedDecl *D) { static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { // Warn if this is used but marked unused. if (D->hasAttr<UnusedAttr>()) { - const Decl *DC = cast<Decl>(S.getCurObjCLexicalContext()); - if (!DC->hasAttr<UnusedAttr>()) + const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext()); + if (DC && !DC->hasAttr<UnusedAttr>()) S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); } } -static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, - NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { +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; +} + +static AvailabilityResult +DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess) { // See if this declaration is unavailable or deprecated. 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()) + if (IDecl->getDefinition()) { D = IDecl->getDefinition(); + Result = D->getAvailability(&Message); + } } - AvailabilityResult Result = D->getAvailability(&Message); + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); @@ -103,7 +135,8 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, } const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (Result == AR_Deprecated || Result == AR_Unavailable) { + if (Result == AR_Deprecated || Result == AR_Unavailable || + AR_NotYetIntroduced) { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); @@ -115,7 +148,6 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, switch (Result) { case AR_Available: - case AR_NotYetIntroduced: break; case AR_Deprecated: @@ -125,6 +157,34 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, ObjCPropertyAccess); break; + case AR_NotYetIntroduced: { + // Don't do this for enums, they can't be redeclared. + if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) + break; + + 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; + + if (Warn) + S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc, + UnknownObjCClass, ObjCPDecl, + ObjCPropertyAccess); + break; + } + case AR_Unavailable: if (S.getCurContextAvailability() != AR_Unavailable) S.EmitAvailabilityWarning(Sema::AD_Unavailable, @@ -307,7 +367,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, DeduceReturnType(FD, Loc)) return true; } - DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess); + DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, + ObjCPropertyAccess); DiagnoseUnusedOfDecl(*this, D, Loc); @@ -405,12 +466,11 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, SourceLocation MissingNilLoc = PP.getLocForEndOfToken(sentinelExpr->getLocEnd()); std::string NullValue; - if (calleeType == CT_Method && - PP.getIdentifierInfo("nil")->hasMacroDefinition()) + if (calleeType == CT_Method && PP.isMacroDefined("nil")) NullValue = "nil"; else if (getLangOpts().CPlusPlus11) NullValue = "nullptr"; - else if (PP.getIdentifierInfo("NULL")->hasMacroDefinition()) + else if (PP.isMacroDefined("NULL")) NullValue = "NULL"; else NullValue = "(void*) 0"; @@ -3266,7 +3326,9 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Ty == Context.DoubleTy) { if (getLangOpts().SinglePrecisionConstants) { Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); - } else if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp64) { + } else if (getLangOpts().OpenCL && + !((getLangOpts().OpenCLVersion >= 120) || + getOpenCLOptions().cl_khr_fp64)) { Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64); Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); } @@ -3322,6 +3384,9 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Diag(Tok.getLocation(), diag::err_int128_unsupported); Width = MaxWidth; Ty = Context.getIntMaxType(); + } else if (Literal.MicrosoftInteger == 8 && !Literal.isUnsigned) { + Width = 8; + Ty = Context.CharTy; } else { Width = Literal.MicrosoftInteger; Ty = Context.getIntTypeForBitwidth(Width, @@ -4558,6 +4623,83 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { return hasInvalid; } +/// If a builtin function has a pointer argument with no explicit address +/// space, than it should be able to accept a pointer to any address +/// space as input. In order to do this, we need to replace the +/// standard builtin declaration with one that uses the same address space +/// as the call. +/// +/// \returns nullptr If this builtin is not a candidate for a rewrite i.e. +/// it does not contain any pointer arguments without +/// an address space qualifer. Otherwise the rewritten +/// FunctionDecl is returned. +/// TODO: Handle pointer return types. +static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, + const FunctionDecl *FDecl, + MultiExprArg ArgExprs) { + + QualType DeclType = FDecl->getType(); + const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(DeclType); + + if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || + !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams()) + return nullptr; + + bool NeedsNewDecl = false; + unsigned i = 0; + SmallVector<QualType, 8> OverloadParams; + + for (QualType ParamType : FT->param_types()) { + + // Convert array arguments to pointer to simplify type lookup. + Expr *Arg = Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]).get(); + QualType ArgType = Arg->getType(); + if (!ParamType->isPointerType() || + ParamType.getQualifiers().hasAddressSpace() || + !ArgType->isPointerType() || + !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) { + OverloadParams.push_back(ParamType); + continue; + } + + NeedsNewDecl = true; + unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace(); + + QualType PointeeType = ParamType->getPointeeType(); + PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); + OverloadParams.push_back(Context.getPointerType(PointeeType)); + } + + if (!NeedsNewDecl) + return nullptr; + + FunctionProtoType::ExtProtoInfo EPI; + QualType OverloadTy = Context.getFunctionType(FT->getReturnType(), + OverloadParams, EPI); + DeclContext *Parent = Context.getTranslationUnitDecl(); + FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent, + FDecl->getLocation(), + FDecl->getLocation(), + FDecl->getIdentifier(), + OverloadTy, + /*TInfo=*/nullptr, + SC_Extern, false, + /*hasPrototype=*/true); + SmallVector<ParmVarDecl*, 16> Params; + FT = cast<FunctionProtoType>(OverloadTy); + for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { + QualType ParamType = FT->getParamType(i); + ParmVarDecl *Parm = + ParmVarDecl::Create(Context, OverloadDecl, SourceLocation(), + SourceLocation(), nullptr, ParamType, + /*TInfo=*/nullptr, SC_None, nullptr); + Parm->setScopeInfo(0, i); + Params.push_back(Parm); + } + OverloadDecl->setParams(Params); + return OverloadDecl; +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -4661,10 +4803,24 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn)) if (UnOp->getOpcode() == UO_AddrOf) NakedFn = UnOp->getSubExpr()->IgnoreParens(); - - if (isa<DeclRefExpr>(NakedFn)) + + if (isa<DeclRefExpr>(NakedFn)) { NDecl = cast<DeclRefExpr>(NakedFn)->getDecl(); - else if (isa<MemberExpr>(NakedFn)) + + FunctionDecl *FDecl = dyn_cast<FunctionDecl>(NDecl); + if (FDecl && FDecl->getBuiltinID()) { + // Rewrite the function decl for this builtin by replacing paramaters + // with no explicit address space with the address space of the arguments + // in ArgExprs. + if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) { + NDecl = FDecl; + Fn = DeclRefExpr::Create(Context, FDecl->getQualifierLoc(), + SourceLocation(), FDecl, false, + SourceLocation(), FDecl->getType(), + Fn->getValueKind(), FDecl); + } + } + } else if (isa<MemberExpr>(NakedFn)) NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) { @@ -5516,47 +5672,24 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, } /// \brief Return false if the condition expression is valid, true otherwise. -static bool checkCondition(Sema &S, Expr *Cond) { +static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { QualType CondTy = Cond->getType(); + // OpenCL v1.1 s6.3.i says the condition cannot be a floating point type. + if (S.getLangOpts().OpenCL && CondTy->isFloatingType()) { + S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_nonfloat) + << CondTy << Cond->getSourceRange(); + return true; + } + // C99 6.5.15p2 if (CondTy->isScalarType()) return false; - // OpenCL v1.1 s6.3.i says the condition is allowed to be a vector or scalar. - if (S.getLangOpts().OpenCL && CondTy->isVectorType()) - return false; - - // Emit the proper error message. - S.Diag(Cond->getLocStart(), S.getLangOpts().OpenCL ? - diag::err_typecheck_cond_expect_scalar : - diag::err_typecheck_cond_expect_scalar_or_vector) - << CondTy; + S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_scalar) + << CondTy << Cond->getSourceRange(); return true; } -/// \brief Return false if the two expressions can be converted to a vector, -/// true otherwise -static bool checkConditionalConvertScalarsToVectors(Sema &S, ExprResult &LHS, - ExprResult &RHS, - QualType CondTy) { - // Both operands should be of scalar type. - if (!LHS.get()->getType()->isScalarType()) { - S.Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return true; - } - if (!RHS.get()->getType()->isScalarType()) { - S.Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return true; - } - - // Implicity convert these scalars to the type of the condition. - LHS = S.ImpCastExprToType(LHS.get(), CondTy, CK_IntegralCast); - RHS = S.ImpCastExprToType(RHS.get(), CondTy, CK_IntegralCast); - return false; -} - /// \brief Handle when one or both operands are void type. static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, ExprResult &RHS) { @@ -5773,6 +5906,184 @@ static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int, return true; } +/// \brief Simple conversion between integer and floating point types. +/// +/// Used when handling the OpenCL conditional operator where the +/// condition is a vector while the other operands are scalar. +/// +/// OpenCL v1.1 s6.3.i and s6.11.6 together require that the scalar +/// types are either integer or floating type. Between the two +/// operands, the type with the higher rank is defined as the "result +/// type". The other operand needs to be promoted to the same type. No +/// other type promotion is allowed. We cannot use +/// UsualArithmeticConversions() for this purpose, since it always +/// promotes promotable types. +static QualType OpenCLArithmeticConversions(Sema &S, ExprResult &LHS, + ExprResult &RHS, + SourceLocation QuestionLoc) { + LHS = S.DefaultFunctionArrayLvalueConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get()); + if (RHS.isInvalid()) + return QualType(); + + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType LHSType = + S.Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); + QualType RHSType = + S.Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); + + if (!LHSType->isIntegerType() && !LHSType->isRealFloatingType()) { + S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_int_float) + << LHSType << LHS.get()->getSourceRange(); + return QualType(); + } + + if (!RHSType->isIntegerType() && !RHSType->isRealFloatingType()) { + S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_int_float) + << RHSType << RHS.get()->getSourceRange(); + return QualType(); + } + + // If both types are identical, no conversion is needed. + if (LHSType == RHSType) + return LHSType; + + // Now handle "real" floating types (i.e. float, double, long double). + if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) + return handleFloatConversion(S, LHS, RHS, LHSType, RHSType, + /*IsCompAssign = */ false); + + // Finally, we have two differing integer types. + return handleIntegerConversion<doIntegralCast, doIntegralCast> + (S, LHS, RHS, LHSType, RHSType, /*IsCompAssign = */ false); +} + +/// \brief Convert scalar operands to a vector that matches the +/// condition in length. +/// +/// Used when handling the OpenCL conditional operator where the +/// condition is a vector while the other operands are scalar. +/// +/// We first compute the "result type" for the scalar operands +/// according to OpenCL v1.1 s6.3.i. Both operands are then converted +/// into a vector of that type where the length matches the condition +/// vector type. s6.11.6 requires that the element types of the result +/// and the condition must have the same number of bits. +static QualType +OpenCLConvertScalarsToVectors(Sema &S, ExprResult &LHS, ExprResult &RHS, + QualType CondTy, SourceLocation QuestionLoc) { + QualType ResTy = OpenCLArithmeticConversions(S, LHS, RHS, QuestionLoc); + if (ResTy.isNull()) return QualType(); + + const VectorType *CV = CondTy->getAs<VectorType>(); + assert(CV); + + // Determine the vector result type + unsigned NumElements = CV->getNumElements(); + QualType VectorTy = S.Context.getExtVectorType(ResTy, NumElements); + + // Ensure that all types have the same number of bits + if (S.Context.getTypeSize(CV->getElementType()) + != S.Context.getTypeSize(ResTy)) { + // Since VectorTy is created internally, it does not pretty print + // with an OpenCL name. Instead, we just print a description. + std::string EleTyName = ResTy.getUnqualifiedType().getAsString(); + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << "(vector of " << NumElements << " '" << EleTyName << "' values)"; + S.Diag(QuestionLoc, diag::err_conditional_vector_element_size) + << CondTy << OS.str(); + return QualType(); + } + + // Convert operands to the vector result type + LHS = S.ImpCastExprToType(LHS.get(), VectorTy, CK_VectorSplat); + RHS = S.ImpCastExprToType(RHS.get(), VectorTy, CK_VectorSplat); + + return VectorTy; +} + +/// \brief Return false if this is a valid OpenCL condition vector +static bool checkOpenCLConditionVector(Sema &S, Expr *Cond, + SourceLocation QuestionLoc) { + // OpenCL v1.1 s6.11.6 says the elements of the vector must be of + // integral type. + const VectorType *CondTy = Cond->getType()->getAs<VectorType>(); + assert(CondTy); + QualType EleTy = CondTy->getElementType(); + if (EleTy->isIntegerType()) return false; + + S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_nonfloat) + << Cond->getType() << Cond->getSourceRange(); + return true; +} + +/// \brief Return false if the vector condition type and the vector +/// result type are compatible. +/// +/// OpenCL v1.1 s6.11.6 requires that both vector types have the same +/// number of elements, and their element types have the same number +/// of bits. +static bool checkVectorResult(Sema &S, QualType CondTy, QualType VecResTy, + SourceLocation QuestionLoc) { + const VectorType *CV = CondTy->getAs<VectorType>(); + const VectorType *RV = VecResTy->getAs<VectorType>(); + assert(CV && RV); + + if (CV->getNumElements() != RV->getNumElements()) { + S.Diag(QuestionLoc, diag::err_conditional_vector_size) + << CondTy << VecResTy; + return true; + } + + QualType CVE = CV->getElementType(); + QualType RVE = RV->getElementType(); + + if (S.Context.getTypeSize(CVE) != S.Context.getTypeSize(RVE)) { + S.Diag(QuestionLoc, diag::err_conditional_vector_element_size) + << CondTy << VecResTy; + return true; + } + + return false; +} + +/// \brief Return the resulting type for the conditional operator in +/// OpenCL (aka "ternary selection operator", OpenCL v1.1 +/// s6.3.i) when the condition is a vector type. +static QualType +OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, + ExprResult &LHS, ExprResult &RHS, + SourceLocation QuestionLoc) { + Cond = S.DefaultFunctionArrayLvalueConversion(Cond.get()); + if (Cond.isInvalid()) + return QualType(); + QualType CondTy = Cond.get()->getType(); + + if (checkOpenCLConditionVector(S, Cond.get(), QuestionLoc)) + return QualType(); + + // If either operand is a vector then find the vector type of the + // result as specified in OpenCL v1.1 s6.3.i. + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc, + /*isCompAssign*/false); + if (VecResTy.isNull()) return QualType(); + // The result type must match the condition type as specified in + // OpenCL v1.1 s6.11.6. + if (checkVectorResult(S, CondTy, VecResTy, QuestionLoc)) + return QualType(); + return VecResTy; + } + + // Both operands are scalar. + return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc); +} + /// Note that LHS is not null here, even if this is the gnu "x ?: y" extension. /// In that case, LHS = cond. /// C99 6.5.15 @@ -5796,11 +6107,16 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, VK = VK_RValue; OK = OK_Ordinary; + // The OpenCL operator with a vector condition is sufficiently + // different to merit its own checker. + if (getLangOpts().OpenCL && Cond.get()->getType()->isVectorType()) + return OpenCLCheckVectorConditional(*this, Cond, LHS, RHS, QuestionLoc); + // First, check the condition. Cond = UsualUnaryConversions(Cond.get()); if (Cond.isInvalid()) return QualType(); - if (checkCondition(*this, Cond.get())) + if (checkCondition(*this, Cond.get(), QuestionLoc)) return QualType(); // Now check the two expressions. @@ -5812,17 +6128,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - QualType CondTy = Cond.get()->getType(); QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); - // If the condition is a vector, and both operands are scalar, - // attempt to implicity convert them to the vector type to act like the - // built in select. (OpenCL v1.1 s6.3.i) - if (getLangOpts().OpenCL && CondTy->isVectorType()) - if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy)) - return QualType(); - // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { @@ -6116,6 +6424,8 @@ static bool ExprLooksBoolean(Expr *E) { return IsLogicOp(OP->getOpcode()); if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E)) return OP->getOpcode() == UO_LNot; + if (E->getType()->isPointerType()) + return true; return false; } @@ -6218,6 +6528,8 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, DiagnoseConditionalPrecedence(*this, QuestionLoc, Cond.get(), LHS.get(), RHS.get()); + CheckBoolLikeConversion(Cond.get(), QuestionLoc); + if (!commonExpr) return new (Context) ConditionalOperator(Cond.get(), QuestionLoc, LHS.get(), ColonLoc, @@ -7178,9 +7490,12 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, /// \returns True if pointer has incomplete type static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, Expr *Operand) { - assert(Operand->getType()->isAnyPointerType() && - !Operand->getType()->isDependentType()); - QualType PointeeTy = Operand->getType()->getPointeeType(); + QualType ResType = Operand->getType(); + if (const AtomicType *ResAtomicType = ResType->getAs<AtomicType>()) + ResType = ResAtomicType->getValueType(); + + assert(ResType->isAnyPointerType() && !ResType->isDependentType()); + QualType PointeeTy = ResType->getPointeeType(); return S.RequireCompleteType(Loc, PointeeTy, diag::err_typecheck_arithmetic_incomplete_type, PointeeTy, Operand->getSourceRange()); @@ -7196,9 +7511,13 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, /// \returns True when the operand is valid to use (even if as an extension). static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, Expr *Operand) { - if (!Operand->getType()->isAnyPointerType()) return true; + QualType ResType = Operand->getType(); + if (const AtomicType *ResAtomicType = ResType->getAs<AtomicType>()) + ResType = ResAtomicType->getValueType(); - QualType PointeeTy = Operand->getType()->getPointeeType(); + if (!ResType->isAnyPointerType()) return true; + + QualType PointeeTy = ResType->getPointeeType(); if (PointeeTy->isVoidType()) { diagnoseArithmeticOnVoidPointer(S, Loc, Operand); return !S.getLangOpts().CPlusPlus; @@ -7558,7 +7877,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, llvm::APSInt Right; // Check right/shifter operand if (RHS.get()->isValueDependent() || - !RHS.get()->isIntegerConstantExpr(Right, S.Context)) + !RHS.get()->EvaluateAsInt(Right, S.Context)) return; if (Right.isNegative()) { @@ -7605,7 +7924,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, // turned off separately if needed. if (LeftBits == ResultBits - 1) { S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) - << HexResult.str() << LHSType + << HexResult << LHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return; } @@ -7616,6 +7935,69 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, << RHS.get()->getSourceRange(); } +/// \brief Return the resulting type when an OpenCL vector is shifted +/// by a scalar or vector shift amount. +static QualType checkOpenCLVectorShift(Sema &S, + ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign) { + // OpenCL v1.1 s6.3.j says RHS can be a vector only if LHS is a vector. + if (!LHS.get()->getType()->isVectorType()) { + S.Diag(Loc, diag::err_shift_rhs_only_vector) + << RHS.get()->getType() << LHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } + + if (!IsCompAssign) { + LHS = S.UsualUnaryConversions(LHS.get()); + if (LHS.isInvalid()) return QualType(); + } + + RHS = S.UsualUnaryConversions(RHS.get()); + if (RHS.isInvalid()) return QualType(); + + QualType LHSType = LHS.get()->getType(); + const VectorType *LHSVecTy = LHSType->getAs<VectorType>(); + QualType LHSEleType = LHSVecTy->getElementType(); + + // Note that RHS might not be a vector. + QualType RHSType = RHS.get()->getType(); + const VectorType *RHSVecTy = RHSType->getAs<VectorType>(); + QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType; + + // OpenCL v1.1 s6.3.j says that the operands need to be integers. + if (!LHSEleType->isIntegerType()) { + S.Diag(Loc, diag::err_typecheck_expect_int) + << LHS.get()->getType() << LHS.get()->getSourceRange(); + return QualType(); + } + + if (!RHSEleType->isIntegerType()) { + S.Diag(Loc, diag::err_typecheck_expect_int) + << RHS.get()->getType() << RHS.get()->getSourceRange(); + return QualType(); + } + + if (RHSVecTy) { + // OpenCL v1.1 s6.3.j says that for vector types, the operators + // are applied component-wise. So if RHS is a vector, then ensure + // that the number of elements is the same as LHS... + if (RHSVecTy->getNumElements() != LHSVecTy->getNumElements()) { + S.Diag(Loc, diag::err_typecheck_vector_lengths_not_equal) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } + } else { + // ...else expand RHS to match the number of elements in LHS. + QualType VecTy = + S.Context.getExtVectorType(RHSEleType, LHSVecTy->getNumElements()); + RHS = S.ImpCastExprToType(RHS.get(), VecTy, CK_VectorSplat); + } + + return LHSType; +} + // C99 6.5.7 QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc, @@ -7624,8 +8006,11 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, // Vector shifts promote their scalar inputs to vector type. if (LHS.get()->getType()->isVectorType() || - RHS.get()->getType()->isVectorType()) + RHS.get()->getType()->isVectorType()) { + if (LangOpts.OpenCL) + return checkOpenCLVectorShift(*this, LHS, RHS, Loc, IsCompAssign); return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); + } // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 @@ -7807,8 +8192,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) { if (Type->isObjCIdType()) { // For 'id', just check the global pool. Method = S.LookupInstanceMethodInGlobalPool(IsEqualSel, SourceRange(), - /*receiverId=*/true, - /*warn=*/false); + /*receiverId=*/true); } else { // Check protocols. Method = S.LookupMethodInQualifiedType(IsEqualSel, Type, @@ -8614,6 +8998,139 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { return (isa<BlockDecl>(DC) ? NCCK_Block : NCCK_Lambda); } +static bool IsTypeModifiable(QualType Ty, bool IsDereference) { + Ty = Ty.getNonReferenceType(); + if (IsDereference && Ty->isPointerType()) + Ty = Ty->getPointeeType(); + return !Ty.isConstQualified(); +} + +/// Emit the "read-only variable not assignable" error and print notes to give +/// more information about why the variable is not assignable, such as pointing +/// to the declaration of a const variable, showing that a method is const, or +/// that the function is returning a const reference. +static void DiagnoseConstAssignment(Sema &S, const Expr *E, + SourceLocation Loc) { + // Update err_typecheck_assign_const and note_typecheck_assign_const + // when this enum is changed. + enum { + ConstFunction, + ConstVariable, + ConstMember, + ConstMethod, + ConstUnknown, // Keep as last element + }; + + SourceRange ExprRange = E->getSourceRange(); + + // Only emit one error on the first const found. All other consts will emit + // a note to the error. + bool DiagnosticEmitted = false; + + // Track if the current expression is the result of a derefence, and if the + // next checked expression is the result of a derefence. + bool IsDereference = false; + bool NextIsDereference = false; + + // Loop to process MemberExpr chains. + while (true) { + IsDereference = NextIsDereference; + NextIsDereference = false; + + E = E->IgnoreParenImpCasts(); + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + NextIsDereference = ME->isArrow(); + const ValueDecl *VD = ME->getMemberDecl(); + if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) { + // Mutable fields can be modified even if the class is const. + if (Field->isMutable()) { + assert(DiagnosticEmitted && "Expected diagnostic not emitted."); + break; + } + + if (!IsTypeModifiable(Field->getType(), IsDereference)) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) + << ExprRange << ConstMember << false /*static*/ << Field + << Field->getType(); + DiagnosticEmitted = true; + } + S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) + << ConstMember << false /*static*/ << Field << Field->getType() + << Field->getSourceRange(); + } + E = ME->getBase(); + continue; + } else if (const VarDecl *VDecl = dyn_cast<VarDecl>(VD)) { + if (VDecl->getType().isConstQualified()) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) + << ExprRange << ConstMember << true /*static*/ << VDecl + << VDecl->getType(); + DiagnosticEmitted = true; + } + S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) + << ConstMember << true /*static*/ << VDecl << VDecl->getType() + << VDecl->getSourceRange(); + } + // Static fields do not inherit constness from parents. + break; + } + break; + } // End MemberExpr + break; + } + + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + // Function calls + const FunctionDecl *FD = CE->getDirectCallee(); + if (!IsTypeModifiable(FD->getReturnType(), IsDereference)) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange + << ConstFunction << FD; + DiagnosticEmitted = true; + } + S.Diag(FD->getReturnTypeSourceRange().getBegin(), + diag::note_typecheck_assign_const) + << ConstFunction << FD << FD->getReturnType() + << FD->getReturnTypeSourceRange(); + } + } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + // Point to variable declaration. + if (const ValueDecl *VD = DRE->getDecl()) { + if (!IsTypeModifiable(VD->getType(), IsDereference)) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) + << ExprRange << ConstVariable << VD << VD->getType(); + DiagnosticEmitted = true; + } + S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) + << ConstVariable << VD << VD->getType() << VD->getSourceRange(); + } + } + } else if (isa<CXXThisExpr>(E)) { + if (const DeclContext *DC = S.getFunctionLevelDeclContext()) { + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { + if (MD->isConst()) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange + << ConstMethod << MD; + DiagnosticEmitted = true; + } + S.Diag(MD->getLocation(), diag::note_typecheck_assign_const) + << ConstMethod << MD << MD->getSourceRange(); + } + } + } + } + + if (DiagnosticEmitted) + return; + + // Can't determine a more specific message, so display the generic error. + S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown; +} + /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { @@ -8630,8 +9147,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { bool NeedType = false; switch (IsLV) { // C99 6.5.16p2 case Expr::MLV_ConstQualified: - DiagID = diag::err_typecheck_assign_const; - // Use a specialized diagnostic when we're assigning to an object // from an enclosing function or block. if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) { @@ -8670,14 +9185,24 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { if (Loc != OrigLoc) Assign = SourceRange(OrigLoc, OrigLoc); S.Diag(Loc, DiagID) << E->getSourceRange() << Assign; - // We need to preserve the AST regardless, so migration tool + // We need to preserve the AST regardless, so migration tool // can do its job. return false; } } } + // If none of the special cases above are triggered, then this is a + // simple const assignment. + if (DiagID == 0) { + DiagnoseConstAssignment(S, E, Loc); + return true; + } + break; + case Expr::MLV_ConstAddrSpace: + DiagnoseConstAssignment(S, E, Loc); + return true; case Expr::MLV_ArrayType: case Expr::MLV_ArrayTemporary: DiagID = diag::err_typecheck_array_not_modifiable_lvalue; @@ -9189,6 +9714,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { !getLangOpts().CPlusPlus) { AddressOfError = AO_Register_Variable; } + } else if (isa<MSPropertyDecl>(dcl)) { + AddressOfError = AO_Property_Expansion; } else if (isa<FunctionTemplateDecl>(dcl)) { return Context.OverloadTy; } else if (isa<FieldDecl>(dcl) || isa<IndirectFieldDecl>(dcl)) { @@ -11443,12 +11970,9 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, bool IsDecltype) { - ExprEvalContexts.push_back( - ExpressionEvaluationContextRecord(NewContext, - ExprCleanupObjects.size(), - ExprNeedsCleanups, - LambdaContextDecl, - IsDecltype)); + ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), + ExprNeedsCleanups, LambdaContextDecl, + IsDecltype); ExprNeedsCleanups = false; if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); @@ -11580,7 +12104,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // We (incorrectly) mark overload resolution as an unevaluated context, so we // can just check that here. Skip the rest of this function if we've already // marked the function as used. - if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) { + if (Func->isUsed(/*CheckUsedAttr=*/false) || + !IsPotentiallyEvaluatedContext(*this)) { // C++11 [temp.inst]p3: // Unless a function template specialization has been explicitly // instantiated or explicitly specialized, the function template @@ -11635,7 +12160,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, return; DefineImplicitDestructor(Loc, Destructor); } - if (Destructor->isVirtual()) + if (Destructor->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) { if (MethodDecl->isOverloadedOperator() && @@ -11655,7 +12180,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion); else DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion); - } else if (MethodDecl->isVirtual()) + } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, MethodDecl->getParent()); } @@ -11727,7 +12252,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (mightHaveNonExternalLinkage(Func)) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); else if (Func->getMostRecentDecl()->isInlined() && - (LangOpts.CPlusPlus || !LangOpts.GNUInline) && + !LangOpts.GNUInline && !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>()) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } @@ -12029,13 +12554,11 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, } /// \brief Create a field within the lambda class for the variable -/// being captured. Handle Array captures. -static ExprResult addAsFieldToClosureType(Sema &S, - LambdaScopeInfo *LSI, - VarDecl *Var, QualType FieldType, - QualType DeclRefType, - SourceLocation Loc, - bool RefersToCapturedVariable) { +/// being captured. +static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, + QualType FieldType, QualType DeclRefType, + SourceLocation Loc, + bool RefersToCapturedVariable) { CXXRecordDecl *Lambda = LSI->Lambda; // Build the non-static data member. @@ -12046,111 +12569,8 @@ static ExprResult addAsFieldToClosureType(Sema &S, Field->setImplicit(true); Field->setAccess(AS_private); Lambda->addDecl(Field); - - // C++11 [expr.prim.lambda]p21: - // When the lambda-expression is evaluated, the entities that - // are captured by copy are used to direct-initialize each - // corresponding non-static data member of the resulting closure - // object. (For array members, the array elements are - // direct-initialized in increasing subscript order.) These - // initializations are performed in the (unspecified) order in - // which the non-static data members are declared. - - // Introduce a new evaluation context for the initialization, so - // that temporaries introduced as part of the capture are retained - // to be re-"exported" from the lambda expression itself. - EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated); - - // C++ [expr.prim.labda]p12: - // An entity captured by a lambda-expression is odr-used (3.2) in - // the scope containing the lambda-expression. - Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, - DeclRefType, VK_LValue, Loc); - Var->setReferenced(true); - Var->markUsed(S.Context); - - // When the field has array type, create index variables for each - // dimension of the array. We use these index variables to subscript - // the source array, and other clients (e.g., CodeGen) will perform - // the necessary iteration with these index variables. - SmallVector<VarDecl *, 4> IndexVariables; - QualType BaseType = FieldType; - QualType SizeType = S.Context.getSizeType(); - LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size()); - while (const ConstantArrayType *Array - = S.Context.getAsConstantArrayType(BaseType)) { - // Create the iteration variable for this array index. - IdentifierInfo *IterationVarName = nullptr; - { - SmallString<8> Str; - llvm::raw_svector_ostream OS(Str); - OS << "__i" << IndexVariables.size(); - IterationVarName = &S.Context.Idents.get(OS.str()); - } - VarDecl *IterationVar - = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, - IterationVarName, SizeType, - S.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None); - IndexVariables.push_back(IterationVar); - LSI->ArrayIndexVars.push_back(IterationVar); - - // Create a reference to the iteration variable. - ExprResult IterationVarRef - = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); - assert(!IterationVarRef.isInvalid() && - "Reference to invented variable cannot fail!"); - IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); - assert(!IterationVarRef.isInvalid() && - "Conversion of invented variable cannot fail!"); - - // Subscript the array with this iteration variable. - ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr( - Ref, Loc, IterationVarRef.get(), Loc); - if (Subscript.isInvalid()) { - S.CleanupVarDeclMarking(); - S.DiscardCleanupsInEvaluationContext(); - return ExprError(); - } - - Ref = Subscript.get(); - BaseType = Array->getElementType(); - } - - // Construct the entity that we will be initializing. For an array, this - // will be first element in the array, which may require several levels - // of array-subscript entities. - SmallVector<InitializedEntity, 4> Entities; - Entities.reserve(1 + IndexVariables.size()); - Entities.push_back( - InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(), - Field->getType(), Loc)); - for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) - Entities.push_back(InitializedEntity::InitializeElement(S.Context, - 0, - Entities.back())); - - InitializationKind InitKind - = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence Init(S, Entities.back(), InitKind, Ref); - ExprResult Result(true); - if (!Init.Diagnose(S, Entities.back(), InitKind, Ref)) - Result = Init.Perform(S, Entities.back(), InitKind, Ref); - - // If this initialization requires any cleanups (e.g., due to a - // default argument to a copy constructor), note that for the - // lambda. - if (S.ExprNeedsCleanups) - LSI->ExprNeedsCleanups = true; - - // Exit the expression evaluation context used for the capture. - S.CleanupVarDeclMarking(); - S.DiscardCleanupsInEvaluationContext(); - return Result; } - - /// \brief Capture the given variable in the lambda. static bool captureInLambda(LambdaScopeInfo *LSI, VarDecl *Var, @@ -12228,14 +12648,9 @@ static bool captureInLambda(LambdaScopeInfo *LSI, } // Capture this variable in the lambda. - Expr *CopyExpr = nullptr; - if (BuildAndDiagnose) { - ExprResult Result = addAsFieldToClosureType(S, LSI, Var, - CaptureType, DeclRefType, Loc, - RefersToCapturedVariable); - if (!Result.isInvalid()) - CopyExpr = Result.get(); - } + if (BuildAndDiagnose) + addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc, + RefersToCapturedVariable); // Compute the type of a reference to this captured variable. if (ByRef) @@ -12254,18 +12669,20 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // Add the capture. if (BuildAndDiagnose) LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable, - Loc, EllipsisLoc, CaptureType, CopyExpr); + Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr); return true; } -bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, - TryCaptureKind Kind, SourceLocation EllipsisLoc, - bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, - const unsigned *const FunctionScopeIndexToStopAt) { - bool Nested = Var->isInitCapture(); +bool Sema::tryCaptureVariable( + VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, + SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, + QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { + // An init-capture is notionally from the context surrounding its + // declaration, but its parent DC is the lambda class. + DeclContext *VarDC = Var->getDeclContext(); + if (Var->isInitCapture()) + VarDC = VarDC->getParent(); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -12281,9 +12698,9 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, } - // If the variable is declared in the current context (and is not an - // init-capture), there is no need to capture it. - if (!Nested && Var->getDeclContext() == DC) return true; + // If the variable is declared in the current context, there is no need to + // capture it. + if (VarDC == DC) return true; // Capture global variables if it is required to use private copy of this // variable. @@ -12301,6 +12718,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, // the variable. CaptureType = Var->getType(); DeclRefType = CaptureType.getNonReferenceType(); + bool Nested = false; bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; do { @@ -12501,7 +12919,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, FunctionScopesIndex--; DC = ParentDC; Explicit = false; - } while (!Var->getDeclContext()->Equals(DC)); + } while (!VarDC->Equals(DC)); // Walk back down the scope stack, (e.g. from outer lambda to inner lambda) // computing the type of the capture at each step, checking type-specific @@ -13740,7 +14158,17 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { // Bound member functions. case BuiltinType::BoundMember: { ExprResult result = E; - tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function), + const Expr *BME = E->IgnoreParens(); + PartialDiagnostic PD = PDiag(diag::err_bound_member_function); + // Try to give a nicer diagnostic if it is a bound member that we recognize. + if (isa<CXXPseudoDestructorExpr>(BME)) { + PD = PDiag(diag::err_dtor_expr_without_call) << /*pseudo-destructor*/ 1; + } else if (const auto *ME = dyn_cast<MemberExpr>(BME)) { + if (ME->getMemberNameInfo().getName().getNameKind() == + DeclarationName::CXXDestructorName) + PD = PDiag(diag::err_dtor_expr_without_call) << /*destructor*/ 0; + } + tryToRecoverWithCall(result, PD, /*complain*/ true); return result; } |