diff options
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 693 |
1 files changed, 547 insertions, 146 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d3d7d8b67c70..929806ac6bfa 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -79,7 +79,8 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { if (const auto *A = D->getAttr<UnusedAttr>()) { // [[maybe_unused]] should not diagnose uses, but __attribute__((unused)) // should diagnose them. - if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) { + if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused && + A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) { 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(); @@ -425,14 +426,6 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); if (Ty->isFunctionType()) { - // If we are here, we are not calling a function but taking - // its address (which is not allowed in OpenCL v1.0 s6.8.a.3). - if (getLangOpts().OpenCL) { - if (Diagnose) - Diag(E->getExprLoc(), diag::err_opencl_taking_function_address); - return ExprError(); - } - if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc())) @@ -722,8 +715,10 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { return ExprError(); E = Res.get(); - // If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to - // double. + // If this is a 'float' or '__fp16' (CVR qualified or typedef) + // promote to double. + // Note that default argument promotion applies only to float (and + // half/fp16); it does not apply to _Float16. const BuiltinType *BTy = Ty->getAs<BuiltinType>(); if (BTy && (BTy->getKind() == BuiltinType::Half || BTy->getKind() == BuiltinType::Float)) { @@ -995,7 +990,7 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, return ResultType; } -/// \brief Hande arithmetic conversion from integer to float. Helper function +/// \brief Handle arithmetic conversion from integer to float. Helper function /// of UsualArithmeticConversions() static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, ExprResult &IntExpr, @@ -1502,8 +1497,9 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), - /*AllowRaw*/false, /*AllowTemplate*/false, - /*AllowStringTemplate*/false) == Sema::LOLR_Error) + /*AllowRaw*/ false, /*AllowTemplate*/ false, + /*AllowStringTemplate*/ false, + /*DiagnoseMissing*/ true) == Sema::LOLR_Error) return ExprError(); return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); @@ -1594,8 +1590,9 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, ArgTy, - /*AllowRaw*/false, /*AllowTemplate*/false, - /*AllowStringTemplate*/true)) { + /*AllowRaw*/ false, /*AllowTemplate*/ false, + /*AllowStringTemplate*/ true, + /*DiagnoseMissing*/ true)) { case LOLR_Cooked: { llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars()); @@ -1628,6 +1625,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { } case LOLR_Raw: case LOLR_Template: + case LOLR_ErrorNoDiagnostic: llvm_unreachable("unexpected literal operator lookup result"); case LOLR_Error: return ExprError(); @@ -2806,6 +2804,8 @@ ExprResult Sema::BuildDeclarationNameExpr( { QualType type = VD->getType(); + if (type.isNull()) + return ExprError(); if (auto *FPT = type->getAs<FunctionProtoType>()) { // C++ [except.spec]p17: // An exception-specification is considered to be needed when: @@ -3250,11 +3250,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // literal or a cooked one. LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, CookedTy, - /*AllowRaw*/true, /*AllowTemplate*/true, - /*AllowStringTemplate*/false)) { + /*AllowRaw*/ true, /*AllowTemplate*/ true, + /*AllowStringTemplate*/ false, + /*DiagnoseMissing*/ !Literal.isImaginary)) { + case LOLR_ErrorNoDiagnostic: + // Lookup failure for imaginary constants isn't fatal, there's still the + // GNU extension producing _Complex types. + break; case LOLR_Error: return ExprError(); - case LOLR_Cooked: { Expr *Lit; if (Literal.isFloatingLiteral()) { @@ -3322,6 +3326,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Ty = Context.FloatTy; else if (Literal.isLong) Ty = Context.LongDoubleTy; + else if (Literal.isFloat16) + Ty = Context.Float16Ty; else if (Literal.isFloat128) Ty = Context.Float128Ty; else @@ -3470,10 +3476,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } // If this is an imaginary literal, create the ImaginaryLiteral wrapper. - if (Literal.isImaginary) + if (Literal.isImaginary) { Res = new (Context) ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); + Diag(Tok.getLocation(), diag::ext_imaginary_constant); + } return Res; } @@ -4477,6 +4485,22 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); // Instantiate the expression. + // + // FIXME: Pass in a correct Pattern argument, otherwise + // getTemplateInstantiationArgs uses the lexical context of FD, e.g. + // + // template<typename T> + // struct A { + // static int FooImpl(); + // + // template<typename Tp> + // // bug: default argument A<T>::FooImpl() is evaluated with 2-level + // // template argument list [[T], [Tp]], should be [[Tp]]. + // friend A<Tp> Foo(int a); + // }; + // + // template<typename T> + // A<T> Foo(int a = A<T>::FooImpl()); MultiLevelTemplateArgumentList MutiLevelArgList = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); @@ -5041,7 +5065,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, } NeedsNewDecl = true; - unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace(); + LangAS AS = ArgType->getPointeeType().getAddressSpace(); QualType PointeeType = ParamType->getPointeeType(); PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); @@ -5104,6 +5128,87 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn, } } +static bool enclosingClassIsRelatedToClassInWhichMembersWereFound( + const UnresolvedMemberExpr *const UME, Sema &S) { + + const auto GetFunctionLevelDCIfCXXClass = + [](Sema &S) -> const CXXRecordDecl * { + const DeclContext *const DC = S.getFunctionLevelDeclContext(); + if (!DC || !DC->getParent()) + return nullptr; + + // If the call to some member function was made from within a member + // function body 'M' return return 'M's parent. + if (const auto *MD = dyn_cast<CXXMethodDecl>(DC)) + return MD->getParent()->getCanonicalDecl(); + // else the call was made from within a default member initializer of a + // class, so return the class. + if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) + return RD->getCanonicalDecl(); + return nullptr; + }; + // If our DeclContext is neither a member function nor a class (in the + // case of a lambda in a default member initializer), we can't have an + // enclosing 'this'. + + const CXXRecordDecl *const CurParentClass = GetFunctionLevelDCIfCXXClass(S); + if (!CurParentClass) + return false; + + // The naming class for implicit member functions call is the class in which + // name lookup starts. + const CXXRecordDecl *const NamingClass = + UME->getNamingClass()->getCanonicalDecl(); + assert(NamingClass && "Must have naming class even for implicit access"); + + // If the unresolved member functions were found in a 'naming class' that is + // related (either the same or derived from) to the class that contains the + // member function that itself contained the implicit member access. + + return CurParentClass == NamingClass || + CurParentClass->isDerivedFrom(NamingClass); +} + +static void +tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + Sema &S, const UnresolvedMemberExpr *const UME, SourceLocation CallLoc) { + + if (!UME) + return; + + LambdaScopeInfo *const CurLSI = S.getCurLambda(); + // Only try and implicitly capture 'this' within a C++ Lambda if it hasn't + // already been captured, or if this is an implicit member function call (if + // it isn't, an attempt to capture 'this' should already have been made). + if (!CurLSI || CurLSI->ImpCaptureStyle == CurLSI->ImpCap_None || + !UME->isImplicitAccess() || CurLSI->isCXXThisCaptured()) + return; + + // Check if the naming class in which the unresolved members were found is + // related (same as or is a base of) to the enclosing class. + + if (!enclosingClassIsRelatedToClassInWhichMembersWereFound(UME, S)) + return; + + + DeclContext *EnclosingFunctionCtx = S.CurContext->getParent()->getParent(); + // If the enclosing function is not dependent, then this lambda is + // capture ready, so if we can capture this, do so. + if (!EnclosingFunctionCtx->isDependentContext()) { + // If the current lambda and all enclosing lambdas can capture 'this' - + // then go ahead and capture 'this' (since our unresolved overload set + // contains at least one non-static member function). + if (!S.CheckCXXThisCapture(CallLoc, /*Explcit*/ false, /*Diagnose*/ false)) + S.CheckCXXThisCapture(CallLoc); + } else if (S.CurContext->isDependentContext()) { + // ... since this is an implicit member reference, that might potentially + // involve a 'this' capture, mark 'this' for potential capture in + // enclosing lambdas. + if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None) + CurLSI->addPotentialThisCapture(CallLoc); + } +} + /// 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. @@ -5152,6 +5257,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } else { + + tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + *this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()), + Fn->getLocStart()); + return new (Context) CallExpr( Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } @@ -5651,8 +5761,8 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { case Type::STK_ObjCObjectPointer: switch (DestTy->getScalarTypeKind()) { case Type::STK_CPointer: { - unsigned SrcAS = SrcTy->getPointeeType().getAddressSpace(); - unsigned DestAS = DestTy->getPointeeType().getAddressSpace(); + LangAS SrcAS = SrcTy->getPointeeType().getAddressSpace(); + LangAS DestAS = DestTy->getPointeeType().getAddressSpace(); if (SrcAS != DestAS) return CK_AddressSpaceConversion; return CK_BitCast; @@ -5924,9 +6034,9 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, // In OpenCL, casts between vectors of different types are not allowed. // (See OpenCL 6.2). if (SrcTy->isVectorType()) { - if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) - || (getLangOpts().OpenCL && - (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) { + if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) || + (getLangOpts().OpenCL && + !Context.hasSameUnqualifiedType(DestTy, SrcTy))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; return ExprError(); @@ -6256,9 +6366,9 @@ 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(); + LangAS ResultAddrSpace = LangAS::Default; + LangAS LAddrSpace = lhQual.getAddressSpace(); + LangAS RAddrSpace = rhQual.getAddressSpace(); if (S.getLangOpts().OpenCL) { // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address // spaces is disallowed. @@ -7132,6 +7242,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, commonExpr = commonRes.get(); } + // If the common expression is a class or array prvalue, materialize it + // so that we can safely refer to it multiple times. + if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() || + commonExpr->getType()->isArrayType())) { + ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr); + if (MatExpr.isInvalid()) + return ExprError(); + commonExpr = MatExpr.get(); + } + opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(), commonExpr->getType(), commonExpr->getValueKind(), @@ -7391,11 +7511,19 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, // usually happen on valid code. OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue); ExprResult RHSPtr = &RHSExpr; - CastKind K = CK_Invalid; + CastKind K; return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false); } +/// This helper function returns true if QT is a vector type that has element +/// type ElementType. +static bool isVector(QualType QT, QualType ElementType) { + if (const VectorType *VT = QT->getAs<VectorType>()) + return VT->getElementType() == ElementType; + return false; +} + /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: @@ -7514,6 +7642,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (unsupportedTypeConversion(*this, LHSType, RHSType)) return Incompatible; + // Disallow assigning a _Complex to a real type in C++ mode since it simply + // discards the imaginary part. + if (getLangOpts().CPlusPlus && RHSType->getAs<ComplexType>() && + !LHSType->getAs<ComplexType>()) + return Incompatible; + // Arithmetic conversions. if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) { @@ -7526,8 +7660,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) { // U* -> T* if (isa<PointerType>(RHSType)) { - unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); - unsigned AddrSpaceR = RHSType->getPointeeType().getAddressSpace(); + LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); + LangAS AddrSpaceR = RHSType->getPointeeType().getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -7562,10 +7696,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // U^ -> void* if (RHSType->getAs<BlockPointerType>()) { if (LHSPointer->getPointeeType()->isVoidType()) { - unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); - unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>() - ->getPointeeType() - .getAddressSpace(); + LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); + LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return Compatible; @@ -7579,12 +7713,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (isa<BlockPointerType>(LHSType)) { // U^ -> T^ if (RHSType->isBlockPointerType()) { - unsigned AddrSpaceL = LHSType->getAs<BlockPointerType>() - ->getPointeeType() - .getAddressSpace(); - unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>() - ->getPointeeType() - .getAddressSpace(); + LangAS AddrSpaceL = LHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); + LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -7769,7 +7903,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, } } - CastKind Kind = CK_Invalid; + CastKind Kind; if (CheckAssignmentConstraints(it->getType(), RHS, Kind) == Compatible) { RHS = ImpCastExprToType(RHS.get(), it->getType(), Kind); @@ -7885,7 +8019,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, } } - CastKind Kind = CK_Invalid; + CastKind Kind; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); @@ -7980,7 +8114,7 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, unsigned &DiagID) { // The conversion to apply to the scalar before splatting it, // if necessary. - CastKind scalarCast = CK_Invalid; + CastKind scalarCast = CK_NoOp; if (vectorEltTy->isIntegralType(S.Context)) { if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() || @@ -8011,13 +8145,32 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, // Adjust scalar if desired. if (scalar) { - if (scalarCast != CK_Invalid) + if (scalarCast != CK_NoOp) *scalar = S.ImpCastExprToType(scalar->get(), vectorEltTy, scalarCast); *scalar = S.ImpCastExprToType(scalar->get(), vectorTy, CK_VectorSplat); } return false; } +/// Convert vector E to a vector with the same number of elements but different +/// element type. +static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) { + const auto *VecTy = E->getType()->getAs<VectorType>(); + assert(VecTy && "Expression E must be a vector"); + QualType NewVecTy = S.Context.getVectorType(ElementType, + VecTy->getNumElements(), + VecTy->getVectorKind()); + + // Look through the implicit cast. Return the subexpression if its type is + // NewVecTy. + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getSubExpr()->getType() == NewVecTy) + return ICE->getSubExpr(); + + auto Cast = ElementType->isIntegerType() ? CK_IntegralCast : CK_FloatingCast; + return S.ImpCastExprToType(E, NewVecTy, Cast); +} + /// Test if a (constant) integer Int can be casted to another integer type /// IntTy without losing precision. static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, @@ -8459,6 +8612,21 @@ static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, << 0 /* one pointer */ << Pointer->getSourceRange(); } +/// \brief Diagnose invalid arithmetic on a null pointer. +/// +/// If \p IsGNUIdiom is true, the operation is using the 'p = (i8*)nullptr + n' +/// idiom, which we recognize as a GNU extension. +/// +static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc, + Expr *Pointer, bool IsGNUIdiom) { + if (IsGNUIdiom) + S.Diag(Loc, diag::warn_gnu_null_ptr_arith) + << Pointer->getSourceRange(); + else + S.Diag(Loc, diag::warn_pointer_arith_null_ptr) + << S.getLangOpts().CPlusPlus << Pointer->getSourceRange(); +} + /// \brief Diagnose invalid arithmetic on two function pointers. static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS) { @@ -8753,6 +8921,21 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, if (!IExp->getType()->isIntegerType()) return InvalidOperands(Loc, LHS, RHS); + // Adding to a null pointer results in undefined behavior. + if (PExp->IgnoreParenCasts()->isNullPointerConstant( + Context, Expr::NPC_ValueDependentIsNotNull)) { + // In C++ adding zero to a null pointer is defined. + llvm::APSInt KnownVal; + if (!getLangOpts().CPlusPlus || + (!IExp->isValueDependent() && + (!IExp->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) { + // Check the conditions to see if this is the 'p = nullptr + n' idiom. + bool IsGNUIdiom = BinaryOperator::isNullPointerArithmeticExtension( + Context, BO_Add, PExp, IExp); + diagnoseArithmeticOnNullPointer(*this, Loc, PExp, IsGNUIdiom); + } + } + if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) return QualType(); @@ -8814,6 +8997,20 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, // The result type of a pointer-int computation is the pointer type. if (RHS.get()->getType()->isIntegerType()) { + // Subtracting from a null pointer should produce a warning. + // The last argument to the diagnose call says this doesn't match the + // GNU int-to-pointer idiom. + if (LHS.get()->IgnoreParenCasts()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) { + // In C++ adding zero to a null pointer is defined. + llvm::APSInt KnownVal; + if (!getLangOpts().CPlusPlus || + (!RHS.get()->isValueDependent() && + (!RHS.get()->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) { + diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false); + } + } + if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get())) return QualType(); @@ -8849,6 +9046,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, LHS.get(), RHS.get())) return QualType(); + // FIXME: Add warnings for nullptr - ptr. + // The pointee type may have zero size. As an extension, a structure or // union may have zero size or an array may have zero length. In this // case subtraction does not make sense. @@ -9124,9 +9323,11 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS, return; // Ignore anonymous enums. - if (!LHSEnumType->getDecl()->getIdentifier()) + if (!LHSEnumType->getDecl()->getIdentifier() && + !LHSEnumType->getDecl()->getTypedefNameForAnonDecl()) return; - if (!RHSEnumType->getDecl()->getIdentifier()) + if (!RHSEnumType->getDecl()->getIdentifier() && + !RHSEnumType->getDecl()->getTypedefNameForAnonDecl()) return; if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) @@ -9614,8 +9815,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } } - unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace(); - unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace(); + LangAS AddrSpaceL = LCanPointeeTy.getAddressSpace(); + LangAS AddrSpaceR = RCanPointeeTy.getAddressSpace(); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; if (LHSIsNull && !RHSIsNull) @@ -10145,22 +10346,23 @@ static bool IsTypeModifiable(QualType Ty, bool IsDereference) { return !Ty.isConstQualified(); } +// Update err_typecheck_assign_const and note_typecheck_assign_const +// when this enum is changed. +enum { + ConstFunction, + ConstVariable, + ConstMember, + ConstMethod, + NestedConstMember, + ConstUnknown, // Keep as last element +}; + /// 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 @@ -10270,6 +10472,66 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E, S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown; } +enum OriginalExprKind { + OEK_Variable, + OEK_Member, + OEK_LValue +}; + +static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, + const RecordType *Ty, + SourceLocation Loc, SourceRange Range, + OriginalExprKind OEK, + bool &DiagnosticEmitted, + bool IsNested = false) { + // We walk the record hierarchy breadth-first to ensure that we print + // diagnostics in field nesting order. + // First, check every field for constness. + for (const FieldDecl *Field : Ty->getDecl()->fields()) { + if (Field->getType().isConstQualified()) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) + << Range << NestedConstMember << OEK << VD + << IsNested << Field; + DiagnosticEmitted = true; + } + S.Diag(Field->getLocation(), diag::note_typecheck_assign_const) + << NestedConstMember << IsNested << Field + << Field->getType() << Field->getSourceRange(); + } + } + // Then, recurse. + for (const FieldDecl *Field : Ty->getDecl()->fields()) { + QualType FTy = Field->getType(); + if (const RecordType *FieldRecTy = FTy->getAs<RecordType>()) + DiagnoseRecursiveConstFields(S, VD, FieldRecTy, Loc, Range, + OEK, DiagnosticEmitted, true); + } +} + +/// Emit an error for the case where a record we are trying to assign to has a +/// const-qualified field somewhere in its hierarchy. +static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E, + SourceLocation Loc) { + QualType Ty = E->getType(); + assert(Ty->isRecordType() && "lvalue was not record?"); + SourceRange Range = E->getSourceRange(); + const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>(); + bool DiagEmitted = false; + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) + DiagnoseRecursiveConstFields(S, ME->getMemberDecl(), RTy, Loc, + Range, OEK_Member, DiagEmitted); + else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + DiagnoseRecursiveConstFields(S, DRE->getDecl(), RTy, Loc, + Range, OEK_Variable, DiagEmitted); + else + DiagnoseRecursiveConstFields(S, nullptr, RTy, Loc, + Range, OEK_LValue, DiagEmitted); + if (!DiagEmitted) + DiagnoseConstAssignment(S, E, Loc); +} + /// 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) { @@ -10345,6 +10607,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_ConstAddrSpace: DiagnoseConstAssignment(S, E, Loc); return true; + case Expr::MLV_ConstQualifiedField: + DiagnoseRecursiveConstFields(S, E, Loc); + return true; case Expr::MLV_ArrayType: case Expr::MLV_ArrayTemporary: DiagID = diag::err_typecheck_array_not_modifiable_lvalue; @@ -10654,7 +10919,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, return QualType(); } // Increment of bool sets it to true, but is deprecated. - S.Diag(OpLoc, S.getLangOpts().CPlusPlus1z ? diag::ext_increment_bool + S.Diag(OpLoc, S.getLangOpts().CPlusPlus17 ? diag::ext_increment_bool : diag::warn_increment_bool) << Op->getSourceRange(); } else if (S.getLangOpts().CPlusPlus && ResType->isEnumeralType()) { @@ -10838,10 +11103,17 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp.get()->IgnoreParens(); - // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. - if (LangOpts.OpenCL && op->getType()->isFunctionType()) { - Diag(op->getExprLoc(), diag::err_opencl_taking_function_address); - return QualType(); + // In OpenCL captures for blocks called as lambda functions + // are located in the private address space. Blocks used in + // enqueue_kernel can be located in a different address space + // depending on a vendor implementation. Thus preventing + // taking an address of the capture to avoid invalid AS casts. + if (LangOpts.OpenCL) { + auto* VarRef = dyn_cast<DeclRefExpr>(op); + if (VarRef && VarRef->refersToEnclosingVariableOrCapture()) { + Diag(op->getExprLoc(), diag::err_opencl_taking_address_capture); + return QualType(); + } } if (getLangOpts().C99) { @@ -11103,6 +11375,7 @@ BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) { case tok::greater: Opc = BO_GT; break; case tok::exclaimequal: Opc = BO_NE; break; case tok::equalequal: Opc = BO_EQ; break; + case tok::spaceship: Opc = BO_Cmp; break; case tok::amp: Opc = BO_And; break; case tok::caret: Opc = BO_Xor; break; case tok::pipe: Opc = BO_Or; break; @@ -11233,6 +11506,70 @@ static NamedDecl *getDeclFromExpr(Expr *E) { return nullptr; } +// This helper function promotes a binary operator's operands (which are of a +// half vector type) to a vector of floats and then truncates the result to +// a vector of either half or short. +static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, + BinaryOperatorKind Opc, QualType ResultTy, + ExprValueKind VK, ExprObjectKind OK, + bool IsCompAssign, SourceLocation OpLoc, + FPOptions FPFeatures) { + auto &Context = S.getASTContext(); + assert((isVector(ResultTy, Context.HalfTy) || + isVector(ResultTy, Context.ShortTy)) && + "Result must be a vector of half or short"); + assert(isVector(LHS.get()->getType(), Context.HalfTy) && + isVector(RHS.get()->getType(), Context.HalfTy) && + "both operands expected to be a half vector"); + + RHS = convertVector(RHS.get(), Context.FloatTy, S); + QualType BinOpResTy = RHS.get()->getType(); + + // If Opc is a comparison, ResultType is a vector of shorts. In that case, + // change BinOpResTy to a vector of ints. + if (isVector(ResultTy, Context.ShortTy)) + BinOpResTy = S.GetSignedVectorType(BinOpResTy); + + if (IsCompAssign) + return new (Context) CompoundAssignOperator( + LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy, + OpLoc, FPFeatures); + + LHS = convertVector(LHS.get(), Context.FloatTy, S); + auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, + VK, OK, OpLoc, FPFeatures); + return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S); +} + +static std::pair<ExprResult, ExprResult> +CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, + Expr *RHSExpr) { + ExprResult LHS = LHSExpr, RHS = RHSExpr; + if (!S.getLangOpts().CPlusPlus) { + // C cannot handle TypoExpr nodes on either side of a binop because it + // doesn't handle dependent types properly, so make sure any TypoExprs have + // been dealt with before checking the operands. + LHS = S.CorrectDelayedTyposInExpr(LHS); + RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) { + if (Opc != BO_Assign) + return ExprResult(E); + // Avoid correcting the RHS to the same Expr as the LHS. + Decl *D = getDeclFromExpr(E); + return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; + }); + } + return std::make_pair(LHS, RHS); +} + +/// Returns true if conversion between vectors of halfs and vectors of floats +/// is needed. +static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, + QualType SrcType) { + return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && + !Ctx.getTargetInfo().useFP16ConversionIntrinsics() && + isVector(SrcType, Ctx.HalfTy); +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -11264,22 +11601,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, QualType CompResultTy; // Type of computation result ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; + bool ConvertHalfVec = false; - if (!getLangOpts().CPlusPlus) { - // C cannot handle TypoExpr nodes on either side of a binop because it - // doesn't handle dependent types properly, so make sure any TypoExprs have - // been dealt with before checking the operands. - LHS = CorrectDelayedTyposInExpr(LHSExpr); - RHS = CorrectDelayedTyposInExpr(RHSExpr, [Opc, LHS](Expr *E) { - if (Opc != BO_Assign) - return ExprResult(E); - // Avoid correcting the RHS to the same Expr as the LHS. - Decl *D = getDeclFromExpr(E); - return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; - }); - if (!LHS.isUsable() || !RHS.isUsable()) - return ExprError(); - } + std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); + if (!LHS.isUsable() || !RHS.isUsable()) + return ExprError(); if (getLangOpts().OpenCL) { QualType LHSTy = LHSExpr->getType(); @@ -11327,6 +11653,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_Mul: case BO_Div: + ConvertHalfVec = true; ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); break; @@ -11334,9 +11661,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); break; case BO_Add: + ConvertHalfVec = true; ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc); break; case BO_Sub: + ConvertHalfVec = true; ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); break; case BO_Shl: @@ -11347,12 +11676,21 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_LT: case BO_GE: case BO_GT: + ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); break; case BO_EQ: case BO_NE: + ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; + case BO_Cmp: + // FIXME: Implement proper semantic checking of '<=>'. + ConvertHalfVec = true; + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); + if (!ResultTy.isNull()) + ResultTy = Context.VoidTy; + break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); LLVM_FALLTHROUGH; @@ -11362,10 +11700,12 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_LAnd: case BO_LOr: + ConvertHalfVec = true; ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc); break; case BO_MulAssign: case BO_DivAssign: + ConvertHalfVec = true; CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; @@ -11379,11 +11719,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AddAssign: + ConvertHalfVec = true; CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_SubAssign: + ConvertHalfVec = true; CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); @@ -11416,6 +11758,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + // Some of the binary operations require promoting operands of half vector to + // float vectors and truncating the result back to half vector. For now, we do + // this only when HalfArgsAndReturn is set (that is, when the target is arm or + // arm64). + assert(isVector(RHS.get()->getType(), Context.HalfTy) == + isVector(LHS.get()->getType(), Context.HalfTy) && + "both sides are half vectors or neither sides are"); + ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, + LHS.get()->getType()); + // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); CheckArrayAccess(RHS.get()); @@ -11438,14 +11790,26 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts())) DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get()); - if (CompResultTy.isNull()) + // Opc is not a compound assignment if CompResultTy is null. + if (CompResultTy.isNull()) { + if (ConvertHalfVec) + return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, + OpLoc, FPFeatures); return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, FPFeatures); + } + + // Handle compound assignments. if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; OK = LHS.get()->getObjectKind(); } + + if (ConvertHalfVec) + return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, + OpLoc, FPFeatures); + return new (Context) CompoundAssignOperator( LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc, FPFeatures); @@ -11693,6 +12057,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { + ExprResult LHS, RHS; + std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); + if (!LHS.isUsable() || !RHS.isUsable()) + return ExprError(); + LHSExpr = LHS.get(); + RHSExpr = RHS.get(); + // We want to end up calling one of checkPseudoObjectAssignment // (if the LHS is a pseudo-object), BuildOverloadedBinOp (if // both expressions are overloadable or either is type-dependent), @@ -11796,6 +12167,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resultType; + bool ConvertHalfVec = false; if (getLangOpts().OpenCL) { QualType Ty = InputExpr->getType(); // The only legal unary operation for atomics is '&'. @@ -11835,6 +12207,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Minus: Input = UsualUnaryConversions(Input.get()); if (Input.isInvalid()) return ExprError(); + // Unary plus and minus require promoting an operand of half vector to a + // float vector and truncating the result back to a half vector. For now, we + // do this only when HalfArgsAndReturns is set (that is, when the target is + // arm or arm64). + ConvertHalfVec = + needsConversionOfHalfVec(true, Context, Input.get()->getType()); + + // If the operand is a half vector, promote it to a float vector. + if (ConvertHalfVec) + Input = convertVector(Input.get(), Context.FloatTy, *this); resultType = Input.get()->getType(); if (resultType->isDependentType()) break; @@ -11972,8 +12354,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Opc != UO_AddrOf && Opc != UO_Deref) CheckArrayAccess(Input.get()); - return new (Context) + auto *UO = new (Context) UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc); + // Convert the result back to a half vector. + if (ConvertHalfVec) + return convertVector(UO, Context.HalfTy, *this); + return UO; } /// \brief Determine whether the given expression is a qualified member @@ -12211,15 +12597,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, && RequireCompleteType(BuiltinLoc, ArgTy, diag::err_offsetof_incomplete_type, TypeRange)) return ExprError(); - - // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a - // GCC extension, diagnose them. - // FIXME: This diagnostic isn't actually visible because the location is in - // a system header! - if (Components.size() != 1) - Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) - << SourceRange(Components[1].LocStart, Components.back().LocEnd); - + bool DidWarnAboutNonPOD = false; QualType CurrentType = ArgTy; SmallVector<OffsetOfNode, 4> Comps; @@ -12482,8 +12860,8 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, // Look for an explicit signature in that function type. FunctionProtoTypeLoc ExplicitSignature; - TypeLoc tmp = Sig->getTypeLoc().IgnoreParens(); - if ((ExplicitSignature = tmp.getAs<FunctionProtoTypeLoc>())) { + if ((ExplicitSignature = + Sig->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>())) { // Check whether that explicit signature was synthesized by // GetTypeForDeclarator. If so, don't save that as part of the @@ -13366,7 +13744,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.isConstantEvaluated() || !getLangOpts().CPlusPlus1z) + if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus17) for (const auto *L : Rec.Lambdas) Diag(L->getLocStart(), D); } else { @@ -13591,29 +13969,21 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { - bool AlreadyInstantiated = false; - SourceLocation PointOfInstantiation = Loc; - if (FunctionTemplateSpecializationInfo *SpecInfo - = Func->getTemplateSpecializationInfo()) { - if (SpecInfo->getPointOfInstantiation().isInvalid()) - SpecInfo->setPointOfInstantiation(Loc); - else if (SpecInfo->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - AlreadyInstantiated = true; - PointOfInstantiation = SpecInfo->getPointOfInstantiation(); - } - } else if (MemberSpecializationInfo *MSInfo - = Func->getMemberSpecializationInfo()) { - if (MSInfo->getPointOfInstantiation().isInvalid()) - MSInfo->setPointOfInstantiation(Loc); - else if (MSInfo->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - AlreadyInstantiated = true; - PointOfInstantiation = MSInfo->getPointOfInstantiation(); - } - } - - if (!AlreadyInstantiated || Func->isConstexpr()) { + TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind(); + SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Func->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } else if (TSK != TSK_ImplicitInstantiation) { + // Use the point of use as the point of instantiation, instead of the + // point of explicit instantiation (which we track as the actual point of + // instantiation). This gives better backtraces in diagnostics. + PointOfInstantiation = Loc; + } + + if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || + Func->isConstexpr()) { if (isa<CXXRecordDecl>(Func->getDeclContext()) && cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() && CodeSynthesisContexts.size()) @@ -13650,6 +14020,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, !LangOpts.GNUInline && !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>()) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); + else if (isExternalWithNoLinkageType(Func)) + UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } Func->markUsed(Context); @@ -13973,8 +14345,13 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { - if (S.IsOpenMPCapturedDecl(Var)) + if (S.IsOpenMPCapturedDecl(Var)) { + bool HasConst = DeclRefType.isConstQualified(); DeclRefType = DeclRefType.getUnqualifiedType(); + // Don't lose diagnostics about assignments to const. + if (HasConst) + DeclRefType.addConst(); + } ByRef = S.IsOpenMPCapturedByRef(Var, RSI->OpenMPLevel); } @@ -13997,6 +14374,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); + if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) + S.setOpenMPCaptureKind(Field, Var, RSI->OpenMPLevel); CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); @@ -14167,6 +14546,7 @@ bool Sema::tryCaptureVariable( bool IsGlobal = !Var->hasLocalStorage(); if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var))) return true; + Var = Var->getCanonicalDecl(); // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -14248,14 +14628,16 @@ bool Sema::tryCaptureVariable( // just break here. Similarly, global variables that are captured in a // target region should not be captured outside the scope of the region. if (RSI->CapRegionKind == CR_OpenMP) { - auto IsTargetCap = isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); + bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel); + auto IsTargetCap = !IsOpenMPPrivateDecl && + isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); // When we detect target captures we are looking from inside the // target region, therefore we need to propagate the capture from the // enclosing region. Therefore, the capture is not initially nested. if (IsTargetCap) - FunctionScopesIndex--; + adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel); - if (IsTargetCap || isOpenMPPrivateDecl(Var, RSI->OpenMPLevel)) { + if (IsTargetCap || IsOpenMPPrivateDecl) { Nested = !IsTargetCap; DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); @@ -14451,9 +14833,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); bool OdrUseContext = isOdrUseContext(SemaRef); + bool UsableInConstantExpr = + Var->isUsableInConstantExpressions(SemaRef.Context); bool NeedDefinition = - OdrUseContext || (isEvaluatableContext(SemaRef) && - Var->isUsableInConstantExpressions(SemaRef.Context)); + OdrUseContext || (isEvaluatableContext(SemaRef) && UsableInConstantExpr); VarTemplateSpecializationDecl *VarSpec = dyn_cast<VarTemplateSpecializationDecl>(Var); @@ -14472,24 +14855,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // instantiations of variable templates, except for those that could be used // in a constant expression. if (NeedDefinition && isTemplateInstantiation(TSK)) { - bool TryInstantiating = TSK == TSK_ImplicitInstantiation; - - if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) { - if (Var->getPointOfInstantiation().isInvalid()) { - // This is a modification of an existing AST node. Notify listeners. - if (ASTMutationListener *L = SemaRef.getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); - } else if (!Var->isUsableInConstantExpressions(SemaRef.Context)) - // Don't bother trying to instantiate it again, unless we might need - // its initializer before we get to the end of the TU. - TryInstantiating = false; - } - - if (Var->getPointOfInstantiation().isInvalid()) - Var->setTemplateSpecializationKind(TSK, Loc); + // Per C++17 [temp.explicit]p10, we may instantiate despite an explicit + // instantiation declaration if a variable is usable in a constant + // expression (among other cases). + bool TryInstantiating = + TSK == TSK_ImplicitInstantiation || + (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr); if (TryInstantiating) { SourceLocation PointOfInstantiation = Var->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } + bool InstantiationDependent = false; bool IsNonDependent = VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments( @@ -14498,11 +14878,17 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // Do not instantiate specializations that are still type-dependent. if (IsNonDependent) { - if (Var->isUsableInConstantExpressions(SemaRef.Context)) { - // Do not defer instantiations of variables which could be used in a + if (UsableInConstantExpr) { + // Do not defer instantiations of variables that could be used in a // constant expression. SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); - } else { + } else if (FirstInstantiation || + isa<VarTemplateSpecializationDecl>(Var)) { + // FIXME: For a specialization of a variable template, we don't + // distinguish between "declaration and type implicitly instantiated" + // and "implicit instantiation of definition requested", so we have + // no direct way to avoid enqueueing the pending instantiation + // multiple times. SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); } @@ -14522,7 +14908,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, IsVariableAConstantExpression(Var, SemaRef.Context)) { // A reference initialized by a constant expression can never be // odr-used, so simply ignore it. - if (!Var->getType()->isReferenceType()) + if (!Var->getType()->isReferenceType() || + (SemaRef.LangOpts.OpenMP && SemaRef.IsOpenMPCapturedDecl(Var))) SemaRef.MaybeODRUseExprs.insert(E); } else if (OdrUseContext) { MarkVarDeclODRUsed(Var, Loc, SemaRef, @@ -14595,7 +14982,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, 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, const Expr *Base) { @@ -14810,10 +15197,24 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, if (Statement && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); + return true; } - else - Diag(Loc, PD); - + + // The initializer of a constexpr variable or of the first declaration of a + // static data member is not syntactically a constant evaluated constant, + // but nonetheless is always required to be a constant expression, so we + // can skip diagnosing. + // FIXME: Using the mangling context here is a hack. + if (auto *VD = dyn_cast_or_null<VarDecl>( + ExprEvalContexts.back().ManglingContextDecl)) { + if (VD->isConstexpr() || + (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline())) + break; + // FIXME: For any other kind of variable, we should build a CFG for its + // initializer and check whether the context in question is reachable. + } + + Diag(Loc, PD); return true; } |