diff options
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 1133 |
1 files changed, 755 insertions, 378 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0f79978b0911..2842add2cc4a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -56,6 +56,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/TypeSize.h" +#include <optional> using namespace clang; using namespace sema; @@ -136,7 +137,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) { /// Determine whether a FunctionDecl was ever declared with an /// explicit storage class. static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { - for (auto I : D->redecls()) { + for (auto *I : D->redecls()) { if (I->getStorageClass() != SC_None) return true; } @@ -222,7 +223,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, - ObjCInterfaceDecl *ClassReceiver) { + ObjCInterfaceDecl *ClassReceiver, + bool SkipTrailingRequiresClause) { SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, @@ -281,9 +283,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, // See if this is a function with constraints that need to be satisfied. // Check this before deducing the return type, as it might instantiate the // definition. - if (FD->getTrailingRequiresClause()) { + if (!SkipTrailingRequiresClause && FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(FD, Satisfaction, Loc)) + if (CheckFunctionConstraints(FD, Satisfaction, Loc, + /*ForOverloadResolution*/ true)) // A diagnostic will have already been generated (non-constant // constraint expression, for example) return true; @@ -349,7 +352,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions // List-items in map clauses on this construct may only refer to the declared // variable var and entities that could be referenced by a procedure defined - // at the same location + // at the same location. + // [OpenMP 5.2] Also allow iterator declared variables. if (LangOpts.OpenMP && isa<VarDecl>(D) && !isOpenMPDeclareMapperVarDeclAllowed(cast<VarDecl>(D))) { Diag(Loc, diag::err_omp_declare_mapper_wrong_var) @@ -837,7 +841,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { E = ImpCastExprToType(E, PTy, CK_IntegralCast).get(); return E; } - if (Ty->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(Ty)) { QualType PT = Context.getPromotedIntegerType(Ty); E = ImpCastExprToType(E, PT, CK_IntegralCast).get(); return E; @@ -976,7 +980,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) { DiagRuntimeBehavior( E->getBeginLoc(), nullptr, PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << Ty << CT); - LLVM_FALLTHROUGH; + [[fallthrough]]; case VAK_Valid: if (Ty->isRecordType()) { // This is unlikely to be what the user intended. If the class has a @@ -1056,7 +1060,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(), - None, E->getEndLoc()); + std::nullopt, E->getEndLoc()); if (Call.isInvalid()) return ExprError(); @@ -1088,7 +1092,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true; if (SkipCast) return false; if (IntTy->isIntegerType()) { - QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType(); + QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType(); IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating); IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, CK_FloatingRealToComplex); @@ -1100,60 +1104,59 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, return false; } +// This handles complex/complex, complex/float, or float/complex. +// When both operands are complex, the shorter operand is converted to the +// type of the longer, and that is the type of the result. This corresponds +// to what is done when combining two real floating-point operands. +// The fun begins when size promotion occur across type domains. +// From H&S 6.3.4: When one operand is complex and the other is a real +// floating-point type, the less precise type is converted, within it's +// real or complex domain, to the precision of the other type. For example, +// when combining a "long double" with a "double _Complex", the +// "double _Complex" is promoted to "long double _Complex". +static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter, + QualType ShorterType, + QualType LongerType, + bool PromotePrecision) { + bool LongerIsComplex = isa<ComplexType>(LongerType.getCanonicalType()); + QualType Result = + LongerIsComplex ? LongerType : S.Context.getComplexType(LongerType); + + if (PromotePrecision) { + if (isa<ComplexType>(ShorterType.getCanonicalType())) { + Shorter = + S.ImpCastExprToType(Shorter.get(), Result, CK_FloatingComplexCast); + } else { + if (LongerIsComplex) + LongerType = LongerType->castAs<ComplexType>()->getElementType(); + Shorter = S.ImpCastExprToType(Shorter.get(), LongerType, CK_FloatingCast); + } + } + return Result; +} + /// Handle arithmetic conversion with complex types. Helper function of /// UsualArithmeticConversions() -static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, - ExprResult &RHS, QualType LHSType, - QualType RHSType, - bool IsCompAssign) { +static QualType handleComplexConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, bool IsCompAssign) { // if we have an integer operand, the result is the complex type. if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, - /*skipCast*/false)) + /*SkipCast=*/false)) return LHSType; if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, - /*skipCast*/IsCompAssign)) + /*SkipCast=*/IsCompAssign)) return RHSType; - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - // Compute the rank of the two types, regardless of whether they are complex. int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType); - - auto *LHSComplexType = dyn_cast<ComplexType>(LHSType); - auto *RHSComplexType = dyn_cast<ComplexType>(RHSType); - QualType LHSElementType = - LHSComplexType ? LHSComplexType->getElementType() : LHSType; - QualType RHSElementType = - RHSComplexType ? RHSComplexType->getElementType() : RHSType; - - QualType ResultType = S.Context.getComplexType(LHSElementType); - if (Order < 0) { + if (Order < 0) // Promote the precision of the LHS if not an assignment. - ResultType = S.Context.getComplexType(RHSElementType); - if (!IsCompAssign) { - if (LHSComplexType) - LHS = - S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast); - else - LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast); - } - } else if (Order > 0) { - // Promote the precision of the RHS. - if (RHSComplexType) - RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast); - else - RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast); - } - return ResultType; + return handleComplexFloatConversion(S, LHS, LHSType, RHSType, + /*PromotePrecision=*/!IsCompAssign); + // Promote the precision of the RHS unless it is already the same as the LHS. + return handleComplexFloatConversion(S, RHS, RHSType, LHSType, + /*PromotePrecision=*/Order > 0); } /// Handle arithmetic conversion from integer to float. Helper function @@ -1539,18 +1542,16 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. - QualType LHSType = - Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); - QualType RHSType = - Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); + QualType LHSType = LHS.get()->getType().getUnqualifiedType(); + QualType RHSType = RHS.get()->getType().getUnqualifiedType(); // For conversion purposes, we ignore any atomic qualifier on the LHS. if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>()) LHSType = AtomicLHS->getValueType(); // If both types are identical, no conversion is needed. - if (LHSType == RHSType) - return LHSType; + if (Context.hasSameType(LHSType, RHSType)) + return Context.getCommonSugaredType(LHSType, RHSType); // If either side is a non-arithmetic type (e.g. a pointer), we are done. // The caller can deal with this (e.g. pointer + int). @@ -1559,7 +1560,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // Apply unary and bitfield promotions to the LHS's type. QualType LHSUnpromotedType = LHSType; - if (LHSType->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(LHSType)) LHSType = Context.getPromotedIntegerType(LHSType); QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); if (!LHSBitfieldPromoteTy.isNull()) @@ -1568,8 +1569,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast); // If both types are identical, no conversion is needed. - if (LHSType == RHSType) - return LHSType; + if (Context.hasSameType(LHSType, RHSType)) + return Context.getCommonSugaredType(LHSType, RHSType); // At this point, we have two different arithmetic types. @@ -1580,8 +1581,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) - return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, - ACK == ACK_CompAssign); + return handleComplexConversion(*this, LHS, RHS, LHSType, RHSType, + ACK == ACK_CompAssign); // Now handle "real" floating types (i.e. float, double, long double). if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) @@ -1624,10 +1625,9 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, Types[i] = nullptr; } - ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, - ControllingExpr, - llvm::makeArrayRef(Types, NumAssocs), - ArgExprs); + ExprResult ER = + CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr, + llvm::ArrayRef(Types, NumAssocs), ArgExprs); delete [] Types; return ER; } @@ -1839,7 +1839,7 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); - if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), + if (S.LookupLiteralOperator(Scope, R, llvm::ArrayRef(ArgTy, Args.size()), /*AllowRaw*/ false, /*AllowTemplate*/ false, /*AllowStringTemplatePack*/ false, /*DiagnoseMissing*/ true) == Sema::LOLR_Error) @@ -1964,8 +1964,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { TemplateArgument Arg(Lit); TemplateArgumentLocInfo ArgInfo(Lit); ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); - return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(), - &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, + StringTokLocs.back(), &ExplicitArgs); } case LOLR_StringTemplatePack: { @@ -1985,8 +1985,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(), - &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, + StringTokLocs.back(), &ExplicitArgs); } case LOLR_Raw: case LOLR_ErrorNoDiagnostic: @@ -2082,9 +2082,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, NestedNameSpecifierLoc NNS, NamedDecl *FoundD, SourceLocation TemplateKWLoc, const TemplateArgumentListInfo *TemplateArgs) { - bool RefersToCapturedVariable = - isa<VarDecl>(D) && - NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc()); + bool RefersToCapturedVariable = isa<VarDecl, BindingDecl>(D) && + NeedToCaptureVariable(D, NameInfo.getLoc()); DeclRefExpr *E = DeclRefExpr::Create( Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty, @@ -2626,7 +2625,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, - None, &TE)) { + std::nullopt, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); @@ -2738,6 +2737,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, ExprResult Sema::BuildQualifiedDeclarationNameExpr( CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) { + if (NameInfo.getName().isDependentName()) + return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, /*TemplateArgs=*/nullptr); + DeclContext *DC = computeDeclContext(SS, false); if (!DC) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), @@ -2947,7 +2950,7 @@ ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) getCurFunction()->recordUseOfWeak(Result); } - if (getLangOpts().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount && !isUnevaluatedContext()) if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); @@ -3187,8 +3190,9 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, /// as an expression. This is only actually called for lookups that /// were not overloaded, and it doesn't promise that the declaration /// will in fact be used. -static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { - if (D->isInvalidDecl()) +static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D, + bool AcceptInvalid) { + if (D->isInvalidDecl() && !AcceptInvalid) return true; if (isa<TypedefNameDecl>(D)) { @@ -3234,7 +3238,8 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // result, because in the overloaded case the results can only be // functions and function templates. if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) && - CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) + CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl(), + AcceptInvalidDecl)) return ExprError(); // Otherwise, just build an unresolved lookup expression. Suppress @@ -3252,8 +3257,9 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ULE; } -static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var); +static void diagnoseUncapturableValueReferenceOrBinding(Sema &S, + SourceLocation loc, + ValueDecl *var); /// Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( @@ -3265,7 +3271,7 @@ ExprResult Sema::BuildDeclarationNameExpr( "Cannot refer unambiguously to a function template"); SourceLocation Loc = NameInfo.getLoc(); - if (CheckDeclInExpr(*this, Loc, D)) { + if (CheckDeclInExpr(*this, Loc, D, AcceptInvalidDecl)) { // Recovery from invalid cases (e.g. D is an invalid Decl). // We use the dependent type for the RecoveryExpr to prevent bogus follow-up // diagnostics, as invalid decls use int as a fallback type. @@ -3391,7 +3397,7 @@ ExprResult Sema::BuildDeclarationNameExpr( valueKind = VK_PRValue; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Decl::ImplicitParam: case Decl::ParmVar: { @@ -3411,20 +3417,11 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } - case Decl::Binding: { + case Decl::Binding: // These are always lvalues. valueKind = VK_LValue; type = type.getNonReferenceType(); - // FIXME: Support lambda-capture of BindingDecls, once CWG actually - // decides how that's supposed to work. - auto *BD = cast<BindingDecl>(VD); - if (BD->getDeclContext() != CurContext) { - auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl()); - if (DD && DD->hasLocalStorage()) - diagnoseUncapturableValueReference(*this, Loc, BD); - } break; - } case Decl::Function: { if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) { @@ -3497,7 +3494,7 @@ ExprResult Sema::BuildDeclarationNameExpr( valueKind = VK_LValue; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Decl::CXXConversion: case Decl::CXXDestructor: @@ -3506,9 +3503,16 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, - /*FIXME: TemplateKWLoc*/ SourceLocation(), - TemplateArgs); + auto *E = + BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, + /*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs); + // Clang AST consumers assume a DeclRefExpr refers to a valid decl. We + // wrap a DeclRefExpr referring to an invalid decl with a dependent-type + // RecoveryExpr to avoid follow-up semantic analysis (thus prevent bogus + // diagnostics). + if (VD->isInvalidDecl() && E) + return CreateRecoveryExpr(E->getBeginLoc(), E->getEndLoc(), {E}); + return E; } static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, @@ -3856,7 +3860,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc, + return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, TokLoc, &ExplicitArgs); } case LOLR_StringTemplatePack: @@ -3949,16 +3953,6 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else { QualType Ty; - // 'long long' is a C99 or C++11 feature. - if (!getLangOpts().C99 && Literal.isLongLong) { - if (getLangOpts().CPlusPlus) - Diag(Tok.getLocation(), - getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); - else - Diag(Tok.getLocation(), diag::ext_c99_longlong); - } - // 'z/uz' literals are a C++2b feature. if (Literal.isSizeT) Diag(Tok.getLocation(), getLangOpts().CPlusPlus @@ -4125,6 +4119,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; Width = LongLongSize; + + // 'long long' is a C99 or C++11 feature, whether the literal + // explicitly specified 'long long' or we needed the extra width. + if (getLangOpts().CPlusPlus) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_longlong + : diag::ext_cxx11_longlong); + else if (!getLangOpts().C99) + Diag(Tok.getLocation(), diag::ext_c99_longlong); } } @@ -4504,7 +4507,6 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::ConstantMatrix: case Type::Record: case Type::Enum: - case Type::Elaborated: case Type::TemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: @@ -4513,6 +4515,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Pipe: case Type::BitInt: llvm_unreachable("type class is never variably-modified!"); + case Type::Elaborated: + T = cast<ElaboratedType>(Ty)->getNamedType(); + break; case Type::Adjusted: T = cast<AdjustedType>(Ty)->getOriginalType(); break; @@ -5011,7 +5016,7 @@ ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, return nullptr; } - if (Optional<llvm::APSInt> Idx = + if (std::optional<llvm::APSInt> Idx = IndexExpr->getIntegerConstantExpr(Context)) { if ((*Idx < 0 || *Idx >= Dim)) { Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range) @@ -5415,6 +5420,10 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, } else { CurContext->addDecl(VD); } + + /// Act on the iterator variable declaration. + ActOnOpenMPIteratorVarDecl(VD); + Expr *Begin = D.Range.Begin; if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) { ExprResult BeginRes = @@ -5434,7 +5443,8 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, IsCorrect = false; continue; } - Optional<llvm::APSInt> Result = Step->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> Result = + Step->getIntegerConstantExpr(Context); // OpenMP 5.0, 2.1.6 Iterators, Restrictions // If the step expression of a range-specification equals zero, the // behavior is unspecified. @@ -5856,8 +5866,10 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, - ParmVarDecl *Param) { + ParmVarDecl *Param, Expr *RewrittenInit, + bool SkipImmediateInvocations) { if (Param->hasUnparsedDefaultArg()) { + assert(!RewrittenInit && "Should not have a rewritten init expression yet"); // If we've already cleared out the location for the default argument, // that means we're parsing it right now. if (!UnparsedDefaultArgLocs.count(Param)) { @@ -5874,11 +5886,14 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, return true; } - if (Param->hasUninstantiatedDefaultArg() && - InstantiateDefaultArgument(CallLoc, FD, Param)) - return true; + if (Param->hasUninstantiatedDefaultArg()) { + assert(!RewrittenInit && "Should not have a rewitten init expression yet"); + if (InstantiateDefaultArgument(CallLoc, FD, Param)) + return true; + } - assert(Param->hasInit() && "default argument but no initializer?"); + Expr *Init = RewrittenInit ? RewrittenInit : Param->getInit(); + assert(Init && "default argument but no initializer?"); // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll @@ -5887,34 +5902,258 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, // bound temporaries; see the comment in PR5810. // We don't need to do that with block decls, though, because // blocks in default argument expression can never capture anything. - if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) { + if (auto *InitWithCleanup = dyn_cast<ExprWithCleanups>(Init)) { // Set the "needs cleanups" bit regardless of whether there are // any explicit objects. - Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects()); - + Cleanup.setExprNeedsCleanups(InitWithCleanup->cleanupsHaveSideEffects()); // Append all the objects to the cleanup list. Right now, this // should always be a no-op, because blocks in default argument // expressions should never be able to capture anything. - assert(!Init->getNumObjects() && + assert(!InitWithCleanup->getNumObjects() && "default argument expression has capturing blocks?"); } - - // We already type-checked the argument, so we know it works. - // Just mark all of the declarations in this potentially-evaluated expression - // as being "referenced". EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); - MarkDeclarationsReferencedInExpr(Param->getDefaultArg(), - /*SkipLocalVariables=*/true); + ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = + SkipImmediateInvocations; + MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables*/ true); return false; } +struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> { + bool HasImmediateCalls = false; + + bool shouldVisitImplicitCode() const { return true; } + + bool VisitCallExpr(CallExpr *E) { + if (const FunctionDecl *FD = E->getDirectCallee()) + HasImmediateCalls |= FD->isConsteval(); + return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E); + } + + // SourceLocExpr are not immediate invocations + // but CXXDefaultInitExpr/CXXDefaultArgExpr containing a SourceLocExpr + // need to be rebuilt so that they refer to the correct SourceLocation and + // DeclContext. + bool VisitSourceLocExpr(SourceLocExpr *E) { + HasImmediateCalls = true; + return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E); + } + + // A nested lambda might have parameters with immediate invocations + // in their default arguments. + // The compound statement is not visited (as it does not constitute a + // subexpression). + // FIXME: We should consider visiting and transforming captures + // with init expressions. + bool VisitLambdaExpr(LambdaExpr *E) { + return VisitCXXMethodDecl(E->getCallOperator()); + } + + // Blocks don't support default parameters, and, as for lambdas, + // we don't consider their body a subexpression. + bool VisitBlockDecl(BlockDecl *B) { return false; } + + bool VisitCompoundStmt(CompoundStmt *B) { return false; } + + bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + return TraverseStmt(E->getExpr()); + } + + bool VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + return TraverseStmt(E->getExpr()); + } +}; + +struct EnsureImmediateInvocationInDefaultArgs + : TreeTransform<EnsureImmediateInvocationInDefaultArgs> { + EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef) + : TreeTransform(SemaRef) {} + + // Lambda can only have immediate invocations in the default + // args of their parameters, which is transformed upon calling the closure. + // The body is not a subexpression, so we have nothing to do. + // FIXME: Immediate calls in capture initializers should be transformed. + ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; } + ExprResult TransformBlockExpr(BlockExpr *E) { return E; } + + // Make sure we don't rebuild the this pointer as it would + // cause it to incorrectly point it to the outermost class + // in the case of nested struct initialization. + ExprResult TransformCXXThisExpr(CXXThisExpr *E) { return E; } +}; + ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, - FunctionDecl *FD, ParmVarDecl *Param) { + FunctionDecl *FD, ParmVarDecl *Param, + Expr *Init) { assert(Param->hasDefaultArg() && "can't build nonexistent default arg"); - if (CheckCXXDefaultArgExpr(CallLoc, FD, Param)) + + bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer(); + + std::optional<ExpressionEvaluationContextRecord::InitializationContext> + InitializationContext = + OutermostDeclarationWithDelayedImmediateInvocations(); + if (!InitializationContext.has_value()) + InitializationContext.emplace(CallLoc, Param, CurContext); + + if (!Init && !Param->hasUnparsedDefaultArg()) { + // Mark that we are replacing a default argument first. + // If we are instantiating a template we won't have to + // retransform immediate calls. + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + + if (Param->hasUninstantiatedDefaultArg()) { + if (InstantiateDefaultArgument(CallLoc, FD, Param)) + return ExprError(); + } + // CWG2631 + // An immediate invocation that is not evaluated where it appears is + // evaluated and checked for whether it is a constant expression at the + // point where the enclosing initializer is used in a function call. + ImmediateCallVisitor V; + if (!NestedDefaultChecking) + V.TraverseDecl(Param); + if (V.HasImmediateCalls) { + ExprEvalContexts.back().DelayedDefaultInitializationContext = { + CallLoc, Param, CurContext}; + EnsureImmediateInvocationInDefaultArgs Immediate(*this); + ExprResult Res = Immediate.TransformInitializer(Param->getInit(), + /*NotCopy=*/false); + if (Res.isInvalid()) + return ExprError(); + Res = ConvertParamDefaultArgument(Param, Res.get(), + Res.get()->getBeginLoc()); + if (Res.isInvalid()) + return ExprError(); + Init = Res.get(); + } + } + + if (CheckCXXDefaultArgExpr( + CallLoc, FD, Param, Init, + /*SkipImmediateInvocations=*/NestedDefaultChecking)) return ExprError(); - return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext); + + return CXXDefaultArgExpr::Create(Context, InitializationContext->Loc, Param, + Init, InitializationContext->Context); +} + +ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { + assert(Field->hasInClassInitializer()); + + // If we might have already tried and failed to instantiate, don't try again. + if (Field->isInvalidDecl()) + return ExprError(); + + auto *ParentRD = cast<CXXRecordDecl>(Field->getParent()); + + std::optional<ExpressionEvaluationContextRecord::InitializationContext> + InitializationContext = + OutermostDeclarationWithDelayedImmediateInvocations(); + if (!InitializationContext.has_value()) + InitializationContext.emplace(Loc, Field, CurContext); + + Expr *Init = nullptr; + + bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer(); + + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Field); + + if (!Field->getInClassInitializer()) { + // Maybe we haven't instantiated the in-class initializer. Go check the + // pattern FieldDecl to see if it has one. + if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { + CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); + DeclContext::lookup_result Lookup = + ClassPattern->lookup(Field->getDeclName()); + + FieldDecl *Pattern = nullptr; + for (auto *L : Lookup) { + if ((Pattern = dyn_cast<FieldDecl>(L))) + break; + } + assert(Pattern && "We must have set the Pattern!"); + if (!Pattern->hasInClassInitializer() || + InstantiateInClassInitializer(Loc, Field, Pattern, + getTemplateInstantiationArgs(Field))) { + Field->setInvalidDecl(); + return ExprError(); + } + } + } + + // CWG2631 + // An immediate invocation that is not evaluated where it appears is + // evaluated and checked for whether it is a constant expression at the + // point where the enclosing initializer is used in a [...] a constructor + // definition, or an aggregate initialization. + ImmediateCallVisitor V; + if (!NestedDefaultChecking) + V.TraverseDecl(Field); + if (V.HasImmediateCalls) { + ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field, + CurContext}; + ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = + NestedDefaultChecking; + + EnsureImmediateInvocationInDefaultArgs Immediate(*this); + + ExprResult Res = + Immediate.TransformInitializer(Field->getInClassInitializer(), + /*CXXDirectInit=*/false); + if (!Res.isInvalid()) + Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc); + if (Res.isInvalid()) { + Field->setInvalidDecl(); + return ExprError(); + } + Init = Res.get(); + } + + if (Field->getInClassInitializer()) { + Expr *E = Init ? Init : Field->getInClassInitializer(); + if (!NestedDefaultChecking) + MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false); + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + ExprResult Res = ActOnFinishFullExpr(E, /*DiscardedValue=*/false); + if (Res.isInvalid()) { + Field->setInvalidDecl(); + return ExprError(); + } + Init = Res.get(); + + return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc, + Field, InitializationContext->Context, + Init); + } + + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // Any attempt to resolve the exception specification of a defaulted default + // constructor before the initializer is lexically complete will ultimately + // come here at which point we can diagnose it. + RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); + Diag(Loc, diag::err_default_member_initializer_not_yet_parsed) + << OutermostClass << Field; + Diag(Field->getEndLoc(), + diag::note_default_member_initializer_not_yet_parsed); + // Recover by marking the field invalid, unless we're in a SFINAE context. + if (!isSFINAEContext()) + Field->setInvalidDecl(); + return ExprError(); } Sema::VariadicCallType @@ -6287,9 +6526,10 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, return; } - Optional<CharUnits> ArgSize = + std::optional<CharUnits> ArgSize = getASTContext().getTypeSizeInCharsIfKnown(ArgCAT); - Optional<CharUnits> ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT); + std::optional<CharUnits> ParmSize = + getASTContext().getTypeSizeInCharsIfKnown(CAT); if (ArgSize && ParmSize && *ArgSize < *ParmSize) { Diag(CallLoc, diag::warn_static_array_too_small) << ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity() @@ -6762,8 +7002,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, nullptr, DRE->isNonOdrUse()); } } - } else if (isa<MemberExpr>(NakedFn)) - NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); + } else if (auto *ME = dyn_cast<MemberExpr>(NakedFn)) + NDecl = ME->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable( @@ -7035,7 +7275,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, TheCall = dyn_cast<CallExpr>(Result.get()); bool CorrectedTypos = TheCall != TheOldCall; if (!TheCall) return Result; - Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); + Args = llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); // A new call expression node was created if some typos were corrected. // However it may not have been constructed with enough storage. In this @@ -8165,23 +8405,6 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { return true; } -/// Handle when one or both operands are void type. -static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, - ExprResult &RHS) { - Expr *LHSExpr = LHS.get(); - Expr *RHSExpr = RHS.get(); - - if (!LHSExpr->getType()->isVoidType()) - S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void) - << RHSExpr->getSourceRange(); - if (!RHSExpr->getType()->isVoidType()) - S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void) - << LHSExpr->getSourceRange(); - LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid); - RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid); - return S.Context.VoidTy; -} - /// Return false if the NullExpr can be promoted to PointerTy, /// true otherwise. static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, @@ -8205,7 +8428,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, if (S.Context.hasSameType(LHSTy, RHSTy)) { // Two identical pointers types are always compatible. - return LHSTy; + return S.Context.getCommonSugaredType(LHSTy, RHSTy); } QualType lhptee, rhptee; @@ -8275,7 +8498,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); - QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); + QualType CompositeTy = S.Context.mergeTypes( + lhptee, rhptee, /*OfBlockPointer=*/false, /*Unqualified=*/false, + /*BlockReturnType=*/false, /*IsConditionalOperator=*/true); if (CompositeTy.isNull()) { // In this situation, we assume void* type. No especially good @@ -8707,7 +8932,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // And if they're both bfloat (which isn't arithmetic), that's fine too. if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) { - return LHSTy; + return Context.getCommonSugaredType(LHSTy, RHSTy); } // If both operands are the same structure or union type, the result is that @@ -8717,16 +8942,37 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHSRT->getDecl() == RHSRT->getDecl()) // "If both the operands have structure or union type, the result has // that type." This implies that CV qualifiers are dropped. - return LHSTy.getUnqualifiedType(); + return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), + RHSTy.getUnqualifiedType()); // FIXME: Type of conditional expression must be complete in C mode. } // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). if (LHSTy->isVoidType() || RHSTy->isVoidType()) { - return checkConditionalVoidType(*this, LHS, RHS); + QualType ResTy; + if (LHSTy->isVoidType() && RHSTy->isVoidType()) { + ResTy = Context.getCommonSugaredType(LHSTy, RHSTy); + } else if (RHSTy->isVoidType()) { + ResTy = RHSTy; + Diag(RHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void) + << RHS.get()->getSourceRange(); + } else { + ResTy = LHSTy; + Diag(LHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void) + << LHS.get()->getSourceRange(); + } + LHS = ImpCastExprToType(LHS.get(), ResTy, CK_ToVoid); + RHS = ImpCastExprToType(RHS.get(), ResTy, CK_ToVoid); + return ResTy; } + // C2x 6.5.15p7: + // ... if both the second and third operands have nullptr_t type, the + // result also has that type. + if (LHSTy->isNullPtrType() && Context.hasSameType(LHSTy, RHSTy)) + return ResTy; + // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy; @@ -8763,7 +9009,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // Allow ?: operations in which both operands have the same // built-in sizeless type. if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy)) - return LHSTy; + return Context.getCommonSugaredType(LHSTy, RHSTy); // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most @@ -9061,8 +9307,8 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin, if (!ResTy->isAnyPointerType()) return ResTy; - auto GetNullability = [&Ctx](QualType Ty) { - Optional<NullabilityKind> Kind = Ty->getNullability(Ctx); + auto GetNullability = [](QualType Ty) { + std::optional<NullabilityKind> Kind = Ty->getNullability(); if (Kind) { // For our purposes, treat _Nullable_result as _Nullable. if (*Kind == NullabilityKind::NullableResult) @@ -9099,7 +9345,7 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin, return ResTy; // Strip all nullability from ResTy. - while (ResTy->getNullability(Ctx)) + while (ResTy->getNullability()) ResTy = ResTy.getSingleStepDesugaredType(Ctx); // Create a new AttributedType with the new nullability kind. @@ -9236,7 +9482,8 @@ static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType, // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. static Sema::AssignConvertType -checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { +checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType, + SourceLocation Loc) { assert(LHSType.isCanonical() && "LHS not canonicalized!"); assert(RHSType.isCanonical() && "RHS not canonicalized!"); @@ -9305,6 +9552,13 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { return Sema::FunctionVoidPointer; } + if (!S.Diags.isIgnored( + diag::warn_typecheck_convert_incompatible_function_pointer_strict, + Loc) && + RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() && + !S.IsFunctionConversion(RHSType, LHSType, RHSType)) + return Sema::IncompatibleFunctionPointerStrict; + // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or // unqualified versions of compatible types, ... QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0); @@ -9656,7 +9910,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, Kind = CK_NoOp; else Kind = CK_BitCast; - return checkPointerTypesForAssignment(*this, LHSType, RHSType); + return checkPointerTypesForAssignment(*this, LHSType, RHSType, + RHS.get()->getBeginLoc()); } // int -> T* @@ -9984,6 +10239,24 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, return Incompatible; } + // This check seems unnatural, however it is necessary to ensure the proper + // conversion of functions/arrays. If the conversion were done for all + // DeclExpr's (created by ActOnIdExpression), it would mess up the unary + // expressions that suppress this implicit conversion (&, sizeof). This needs + // to happen before we check for null pointer conversions because C does not + // undergo the same implicit conversions as C++ does above (by the calls to + // TryImplicitConversion() and PerformImplicitConversion()) which insert the + // lvalue to rvalue cast before checking for null pointer constraints. This + // addresses code like: nullptr_t val; int *ptr; ptr = val; + // + // Suppress this for references: C++ 8.5.3p5. + if (!LHSType->isReferenceType()) { + // FIXME: We potentially allocate here even if ConvertRHS is false. + RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose); + if (RHS.isInvalid()) + return Incompatible; + } + // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() || @@ -10008,18 +10281,6 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, return Compatible; } - // This check seems unnatural, however it is necessary to ensure the proper - // conversion of functions/arrays. If the conversion were done for all - // DeclExpr's (created by ActOnIdExpression), it would mess up the unary - // expressions that suppress this implicit conversion (&, sizeof). - // - // Suppress this for references: C++ 8.5.3p5. - if (!LHSType->isReferenceType()) { - // FIXME: We potentially allocate here even if ConvertRHS is false. - RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose); - if (RHS.isInvalid()) - return Incompatible; - } CastKind Kind; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); @@ -10434,7 +10695,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) - return LHSType; + return Context.getCommonSugaredType(LHSType, RHSType); // If we have compatible AltiVec and GCC vector types, use the AltiVec type. if (LHSVecType && RHSVecType && @@ -11249,7 +11510,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, QualType LHSTy = Context.isPromotableBitField(LHS.get()); if (LHSTy.isNull()) { LHSTy = LHS.get()->getType(); - if (LHSTy->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(LHSTy)) LHSTy = Context.getPromotedIntegerType(LHSTy); } *CompLHSTy = LHSTy; @@ -12268,7 +12529,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we // promote the boolean type, and all other promotable integer types, to // avoid this. - if (IntType->isPromotableIntegerType()) + if (S.Context.isPromotableIntegerType(IntType)) IntType = S.Context.getPromotedIntegerType(IntType); LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast); @@ -12285,7 +12546,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); - Optional<ComparisonCategoryType> CCT = + std::optional<ComparisonCategoryType> CCT = getComparisonCategoryForBuiltinCmp(Type); if (!CCT) return S.InvalidOperands(Loc, LHS, RHS); @@ -12429,7 +12690,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, QualType CompositeTy = LHS.get()->getType(); assert(!CompositeTy->isReferenceType()); - Optional<ComparisonCategoryType> CCT = + std::optional<ComparisonCategoryType> CCT = getComparisonCategoryForBuiltinCmp(CompositeTy); if (!CCT) return InvalidOperands(Loc, LHS, RHS); @@ -12574,34 +12835,54 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return computeResultTy(); } - if (getLangOpts().CPlusPlus) { - // C++ [expr.eq]p4: - // Two operands of type std::nullptr_t or one operand of type - // std::nullptr_t and the other a null pointer constant compare equal. - if (!IsOrdered && LHSIsNull && RHSIsNull) { - if (LHSType->isNullPtrType()) { - RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); - return computeResultTy(); - } - if (RHSType->isNullPtrType()) { - LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return computeResultTy(); - } - } - // Comparison of Objective-C pointers and block pointers against nullptr_t. - // These aren't covered by the composite pointer type rules. - if (!IsOrdered && RHSType->isNullPtrType() && - (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { + // C++ [expr.eq]p4: + // Two operands of type std::nullptr_t or one operand of type + // std::nullptr_t and the other a null pointer constant compare + // equal. + // C2x 6.5.9p5: + // If both operands have type nullptr_t or one operand has type nullptr_t + // and the other is a null pointer constant, they compare equal. + if (!IsOrdered && LHSIsNull && RHSIsNull) { + if (LHSType->isNullPtrType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } - if (!IsOrdered && LHSType->isNullPtrType() && - (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { + if (RHSType->isNullPtrType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } + } + + if (!getLangOpts().CPlusPlus && !IsOrdered && (LHSIsNull || RHSIsNull)) { + // C2x 6.5.9p6: + // Otherwise, at least one operand is a pointer. If one is a pointer and + // the other is a null pointer constant, the null pointer constant is + // converted to the type of the pointer. + if (LHSIsNull && RHSType->isPointerType()) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return computeResultTy(); + } + if (RHSIsNull && LHSType->isPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return computeResultTy(); + } + } + + // Comparison of Objective-C pointers and block pointers against nullptr_t. + // These aren't covered by the composite pointer type rules. + if (!IsOrdered && RHSType->isNullPtrType() && + (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return computeResultTy(); + } + if (!IsOrdered && LHSType->isNullPtrType() && + (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return computeResultTy(); + } + if (getLangOpts().CPlusPlus) { if (IsRelational && ((LHSType->isNullPtrType() && RHSType->isPointerType()) || (RHSType->isNullPtrType() && LHSType->isPointerType()))) { @@ -13152,7 +13433,7 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix"); if (Context.hasSameType(LHSType, RHSType)) - return LHSType; + return Context.getCommonSugaredType(LHSType, RHSType); // Type conversion may change LHS/RHS. Keep copies to the original results, in // case we have to return InvalidOperands. @@ -13196,13 +13477,19 @@ QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS, if (LHSMatType->getNumColumns() != RHSMatType->getNumRows()) return InvalidOperands(Loc, LHS, RHS); - if (!Context.hasSameType(LHSMatType->getElementType(), - RHSMatType->getElementType())) + if (Context.hasSameType(LHSMatType, RHSMatType)) + return Context.getCommonSugaredType( + LHS.get()->getType().getUnqualifiedType(), + RHS.get()->getType().getUnqualifiedType()); + + QualType LHSELTy = LHSMatType->getElementType(), + RHSELTy = RHSMatType->getElementType(); + if (!Context.hasSameType(LHSELTy, RHSELTy)) return InvalidOperands(Loc, LHS, RHS); - return Context.getConstantMatrixType(LHSMatType->getElementType(), - LHSMatType->getNumRows(), - RHSMatType->getNumColumns()); + return Context.getConstantMatrixType( + Context.getCommonSugaredType(LHSELTy, RHSELTy), + LHSMatType->getNumRows(), RHSMatType->getNumColumns()); } return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign); } @@ -13937,19 +14224,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, // type is deprecated unless the assignment is either a discarded-value // expression or an unevaluated operand ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr); - } else { - // C++20 [expr.ass]p6: - // [Compound-assignment] expressions are deprecated if E1 has - // volatile-qualified type and op is not one of the bitwise - // operators |, &, ˆ. - switch (Opc) { - case BO_OrAssign: - case BO_AndAssign: - case BO_XorAssign: - break; - default: - Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType; - } } } @@ -13964,8 +14238,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, return getLangOpts().CPlusPlus ? LHSType : LHSType.getAtomicUnqualifiedType(); } -// Only ignore explicit casts to void. -static bool IgnoreCommaOperand(const Expr *E) { +// Scenarios to ignore if expression E is: +// 1. an explicit cast expression into void +// 2. a function call expression that returns void +static bool IgnoreCommaOperand(const Expr *E, const ASTContext &Context) { E = E->IgnoreParens(); if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { @@ -13980,6 +14256,8 @@ static bool IgnoreCommaOperand(const Expr *E) { } } + if (const auto *CE = dyn_cast<CallExpr>(E)) + return CE->getCallReturnType(Context)->isVoidType(); return false; } @@ -14021,7 +14299,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { } // Only allow some expressions on LHS to not warn. - if (IgnoreCommaOperand(LHS)) + if (IgnoreCommaOperand(LHS, Context)) return; Diag(Loc, diag::warn_comma_operator); @@ -14486,7 +14764,8 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) { /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, - SourceLocation OpLoc) { + SourceLocation OpLoc, + bool IsAfterAmp = false) { if (Op->isTypeDependent()) return S.Context.DependentTy; @@ -14523,18 +14802,18 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, return QualType(); } - // Note that per both C89 and C99, indirection is always legal, even if Result - // is an incomplete type or void. It would be possible to warn about - // dereferencing a void pointer, but it's completely well-defined, and such a - // warning is unlikely to catch any mistakes. In C++, indirection is not valid - // for pointers to 'void' but is fine for any other pointer type: - // - // C++ [expr.unary.op]p1: - // [...] the expression to which [the unary * operator] is applied shall - // be a pointer to an object type, or a pointer to a function type - if (S.getLangOpts().CPlusPlus && Result->isVoidType()) - S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer) - << OpTy << Op->getSourceRange(); + if (Result->isVoidType()) { + // C++ [expr.unary.op]p1: + // [...] the expression to which [the unary * operator] is applied shall + // be a pointer to an object type, or a pointer to a function type + LangOptions LO = S.getLangOpts(); + if (LO.CPlusPlus) + S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer_cpp) + << OpTy << Op->getSourceRange(); + else if (!(LO.C99 && IsAfterAmp) && !S.isUnevaluatedContext()) + S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer) + << OpTy << Op->getSourceRange(); + } // Dereferences are usually l-values... VK = VK_LValue; @@ -14968,7 +15247,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); - LLVM_FALLTHROUGH; + [[fallthrough]]; case BO_Xor: case BO_Or: ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); @@ -15020,7 +15299,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_AndAssign: case BO_OrAssign: // fallthrough DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); - LLVM_FALLTHROUGH; + [[fallthrough]]; case BO_XorAssign: CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); CompLHSTy = CompResultTy; @@ -15163,38 +15442,21 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, Bop->getSourceRange()); } -/// Returns true if the given expression can be evaluated as a constant -/// 'true'. -static bool EvaluatesAsTrue(Sema &S, Expr *E) { - bool Res; - return !E->isValueDependent() && - E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res; -} - -/// Returns true if the given expression can be evaluated as a constant -/// 'false'. -static bool EvaluatesAsFalse(Sema &S, Expr *E) { - bool Res; - return !E->isValueDependent() && - E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res; -} - /// Look for '&&' in the left hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { - // If it's "a && b || 0" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, RHSExpr)) - return; - // If it's "1 && a || b" don't warn since the precedence doesn't matter. - if (!EvaluatesAsTrue(S, Bop->getLHS())) + // If it's "string_literal && a || b" don't warn since the precedence + // doesn't matter. + if (!isa<StringLiteral>(Bop->getLHS()->IgnoreParenImpCasts())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } else if (Bop->getOpcode() == BO_LOr) { if (BinaryOperator *RBop = dyn_cast<BinaryOperator>(Bop->getRHS())) { - // If it's "a || b && 1 || c" we didn't warn earlier for - // "a || b && 1", but warn now. - if (RBop->getOpcode() == BO_LAnd && EvaluatesAsTrue(S, RBop->getRHS())) + // If it's "a || b && string_literal || c" we didn't warn earlier for + // "a || b && string_literal", but warn now. + if (RBop->getOpcode() == BO_LAnd && + isa<StringLiteral>(RBop->getRHS()->IgnoreParenImpCasts())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, RBop); } } @@ -15206,11 +15468,9 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { - // If it's "0 || a && b" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, LHSExpr)) - return; - // If it's "a || b && 1" don't warn since the precedence doesn't matter. - if (!EvaluatesAsTrue(S, Bop->getRHS())) + // If it's "a || b && string_literal" don't warn since the precedence + // doesn't matter. + if (!isa<StringLiteral>(Bop->getRHS()->IgnoreParenImpCasts())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } } @@ -15516,15 +15776,15 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { if (T.isNull() || T->isDependentType()) return false; - if (!T->isPromotableIntegerType()) + if (!Ctx.isPromotableIntegerType(T)) return true; return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); } ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, - UnaryOperatorKind Opc, - Expr *InputExpr) { + UnaryOperatorKind Opc, Expr *InputExpr, + bool IsAfterAmp) { ExprResult Input = InputExpr; ExprValueKind VK = VK_PRValue; ExprObjectKind OK = OK_Ordinary; @@ -15546,7 +15806,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && OpLoc.isValid()) { if (Opc == UO_AddrOf) return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0); if (Opc == UO_Deref) @@ -15574,7 +15834,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Deref: { Input = DefaultFunctionArrayLvalueConversion(Input.get()); if (Input.isInvalid()) return ExprError(); - resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc); + resultType = + CheckIndirectionOperand(*this, Input.get(), VK, OpLoc, IsAfterAmp); break; } case UO_Plus: @@ -15603,6 +15864,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType->castAs<VectorType>()->getVectorKind() != VectorType::AltiVecBool)) break; + else if (resultType->isVLSTBuiltinType()) // SVE vectors allow + and - + break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 Opc == UO_Plus && resultType->isPointerType()) @@ -15792,7 +16055,8 @@ bool Sema::isQualifiedMemberAccess(Expr *E) { } ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, - UnaryOperatorKind Opc, Expr *Input) { + UnaryOperatorKind Opc, Expr *Input, + bool IsAfterAmp) { // First things first: handle placeholders so that the // overloaded-operator check considers the right type. if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) { @@ -15831,13 +16095,14 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input); } - return CreateBuiltinUnaryOp(OpLoc, Opc, Input); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input, IsAfterAmp); } // Unary Operators. 'Tok' is the token for the operator. -ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, Expr *Input) { - return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input); +ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, + Expr *Input, bool IsAfterAmp) { + return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input, + IsAfterAmp); } /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". @@ -15845,8 +16110,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { TheDecl->markUsed(Context); // Create the AST node. The address of a label always has type 'void*'. - return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, - Context.getPointerType(Context.VoidTy)); + auto *Res = new (Context) AddrLabelExpr( + OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); + + if (getCurFunction()) + getCurFunction()->AddrLabels.push_back(Res); + + return Res; } void Sema::ActOnStartStmtExpr() { @@ -16203,7 +16473,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = false; EPI.TypeQuals.addConst(); - T = Context.getFunctionType(Context.DependentTy, None, EPI); + T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI); Sig = Context.getTrivialTypeSourceInfo(T); } @@ -16290,7 +16560,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); // Put the parameter variables in scope. - for (auto AI : CurBlock->TheDecl->parameters()) { + for (auto *AI : CurBlock->TheDecl->parameters()) { AI->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. @@ -16353,10 +16623,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (isa<FunctionNoProtoType>(FTy)) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, None, EPI); + BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); - // Otherwise, if we don't need to change anything about the function type, - // preserve its sugar structure. + // Otherwise, if we don't need to change anything about the function type, + // preserve its sugar structure. } else if (FTy->getReturnType() == RetTy && (!NoReturn || FTy->getNoReturnAttr())) { BlockTy = BSI->FunctionType; @@ -16374,7 +16644,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } else { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); - BlockTy = Context.getFunctionType(RetTy, None, EPI); + BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); } DiagnoseUnusedParameters(BD->parameters()); @@ -16409,8 +16679,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, for (Capture &Cap : BSI->Captures) { if (Cap.isInvalid() || Cap.isThisCapture()) continue; - - VarDecl *Var = Cap.getVariable(); + // Cap.getVariable() is always a VarDecl because + // blocks cannot capture structured bindings or other ValueDecl kinds. + auto *Var = cast<VarDecl>(Cap.getVariable()); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { if (const RecordType *Record = @@ -16603,7 +16874,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). QualType PromoteType; - if (TInfo->getType()->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(TInfo->getType())) { PromoteType = Context.getPromotedIntegerType(TInfo->getType()); // [cstdarg.syn]p1 defers the C++ behavior to what the C standard says, // and C2x 7.16.1.1p2 says, in part: @@ -16664,7 +16935,7 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; - unsigned pw = Context.getTargetInfo().getPointerWidth(0); + unsigned pw = Context.getTargetInfo().getPointerWidth(LangAS::Default); if (pw == Context.getTargetInfo().getIntWidth()) Ty = Context.IntTy; else if (pw == Context.getTargetInfo().getLongWidth()) @@ -16902,6 +17173,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; break; + case IncompatibleFunctionPointerStrict: + DiagKind = + diag::warn_typecheck_convert_incompatible_function_pointer_strict; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; + break; case IncompatibleFunctionPointer: if (getLangOpts().CPlusPlus) { DiagKind = diag::err_typecheck_convert_incompatible_function_pointer; @@ -17492,6 +17769,7 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { if (isUnevaluatedContext() || !E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || + isCheckingDefaultArgumentOrInitializer() || RebuildingImmediateInvocation || isImmediateFunctionContext()) return E; @@ -17537,8 +17815,14 @@ static void EvaluateAndDiagnoseImmediateInvocation( FD = Call->getConstructor(); else llvm_unreachable("unhandled decl kind"); - assert(FD->isConsteval()); + assert(FD && FD->isConsteval()); SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD; + if (auto Context = + SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) { + SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer) + << Context->Decl; + SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at); + } for (auto &Note : Notes) SemaRef.Diag(Note.first, Note.second); return; @@ -17598,6 +17882,11 @@ static void RemoveNestedImmediateInvocation( DRSet.erase(E); return E; } + ExprResult TransformLambdaExpr(LambdaExpr *E) { + // Do not rebuild lambdas to avoid creating a new type. + // Lambdas have already been processed inside their eval context. + return E; + } bool AlwaysRebuild() { return false; } bool ReplacingOriginal() { return true; } bool AllowSkippingCXXConstructExpr() { @@ -17619,9 +17908,13 @@ static void RemoveNestedImmediateInvocation( Transformer.AllowSkippingFirstCXXConstructExpr = false; ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr()); - assert(Res.isUsable()); - Res = SemaRef.MaybeCreateExprWithCleanups(Res); - It->getPointer()->setSubExpr(Res.get()); + // The result may not be usable in case of previous compilation errors. + // In this case evaluation of the expression may result in crash so just + // don't do anything further with the result. + if (Res.isUsable()) { + Res = SemaRef.MaybeCreateExprWithCleanups(Res); + It->getPointer()->setSubExpr(Res.get()); + } } static void @@ -17639,7 +17932,7 @@ HandleImmediateInvocations(Sema &SemaRef, /// Prevent sema calls during the tree transform from adding pointers that /// are already in the sets. - llvm::SaveAndRestore<bool> DisableIITracking( + llvm::SaveAndRestore DisableIITracking( SemaRef.RebuildingImmediateInvocation, true); /// Prevent diagnostic during tree transfrom as they are duplicates @@ -17665,7 +17958,7 @@ HandleImmediateInvocations(Sema &SemaRef, for (auto CE : Rec.ImmediateInvocationCandidates) if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); - for (auto DR : Rec.ReferenceToConsteval) { + for (auto *DR : Rec.ReferenceToConsteval) { auto *FD = cast<FunctionDecl>(DR->getDecl()); SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) << FD; @@ -18106,7 +18399,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } } else { // Walk redefinitions, as some of them may be instantiable. - for (auto i : Func->redecls()) { + for (auto *i : Func->redecls()) { if (!i->isUsed(false) && i->isImplicitlyInstantiable()) MarkFunctionReferenced(Loc, i, MightBeOdrUse); } @@ -18114,6 +18407,16 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, }); } + // If a constructor was defined in the context of a default parameter + // or of another default member initializer (ie a PotentiallyEvaluatedIfUsed + // context), its initializers may not be referenced yet. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { + for (CXXCtorInitializer *Init : Constructor->inits()) { + if (Init->isInClassMemberInitializer()) + MarkDeclarationsReferencedInExpr(Init->getInit()); + } + } + // C++14 [except.spec]p17: // An exception-specification is considered to be needed when: // - the function is odr-used or, if it appears in an unevaluated operand, @@ -18173,10 +18476,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, /// - else capture it in the DeclContext that maps to the /// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. static void -MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, +MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef, const unsigned *const FunctionScopeIndexToStopAt = nullptr) { // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. + VarDecl *Var = V->getPotentiallyDecomposedVarDecl(); + assert(Var && "expected a capturable variable"); + if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && (!Var->isExternallyVisible() || Var->isInline() || SemaRef.isExternalWithNoLinkageType(Var)) && @@ -18187,12 +18493,11 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, } QualType CaptureType, DeclRefType; if (SemaRef.LangOpts.OpenMP) - SemaRef.tryCaptureOpenMPLambdas(Var); - SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/ true, - CaptureType, DeclRefType, - FunctionScopeIndexToStopAt); + SemaRef.tryCaptureOpenMPLambdas(V); + SemaRef.tryCaptureVariable(V, Loc, Sema::TryCapture_Implicit, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/ true, CaptureType, + DeclRefType, FunctionScopeIndexToStopAt); if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) { auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext); @@ -18232,17 +18537,17 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, } } - Var->markUsed(SemaRef.Context); + V->markUsed(SemaRef.Context); } -void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture, +void Sema::MarkCaptureUsedInEnclosingContext(ValueDecl *Capture, SourceLocation Loc, unsigned CapturingScopeIndex) { MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex); } -static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var) { +void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc, + ValueDecl *var) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then @@ -18282,12 +18587,12 @@ static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // capture. } - -static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var, - bool &SubCapturesAreNested, - QualType &CaptureType, - QualType &DeclRefType) { - // Check whether we've already captured it. +static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, + ValueDecl *Var, + bool &SubCapturesAreNested, + QualType &CaptureType, + QualType &DeclRefType) { + // Check whether we've already captured it. if (CSI->CaptureMap.count(Var)) { // If we found a capture, any subcaptures are nested. SubCapturesAreNested = true; @@ -18314,14 +18619,18 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. -static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var, - SourceLocation Loc, - const bool Diagnose, Sema &S) { +static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, + ValueDecl *Var, + SourceLocation Loc, + const bool Diagnose, + Sema &S) { if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); - else if (Var->hasLocalStorage()) { - if (Diagnose) - diagnoseUncapturableValueReference(S, Loc, Var); + + VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl(); + if (Underlying) { + if (Underlying->hasLocalStorage() && Diagnose) + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); } return nullptr; } @@ -18329,9 +18638,12 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl * // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. -static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, - SourceLocation Loc, - const bool Diagnose, Sema &S) { +static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, + SourceLocation Loc, const bool Diagnose, + Sema &S) { + + assert((isa<VarDecl, BindingDecl>(Var)) && + "Only variables and structured bindings can be captured"); bool IsBlock = isa<BlockScopeInfo>(CSI); bool IsLambda = isa<LambdaScopeInfo>(CSI); @@ -18388,17 +18700,28 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, return false; } + if (isa<BindingDecl>(Var)) { + if (!IsLambda || !S.getLangOpts().CPlusPlus) { + if (Diagnose) + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); + return false; + } else if (Diagnose && S.getLangOpts().CPlusPlus) { + S.Diag(Loc, S.LangOpts.CPlusPlus20 + ? diag::warn_cxx17_compat_capture_binding + : diag::ext_capture_binding) + << Var; + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; + } + } + return true; } // Returns true if the capture by block was successful. -static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, - SourceLocation Loc, - const bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, - const bool Nested, - Sema &S, bool Invalid) { +static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var, + SourceLocation Loc, const bool BuildAndDiagnose, + QualType &CaptureType, QualType &DeclRefType, + const bool Nested, Sema &S, bool Invalid) { bool ByRef = false; // Blocks are not allowed to capture arrays, excepting OpenCL. @@ -18462,10 +18785,9 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, return !Invalid; } - /// Capture the given variable in the captured region. static bool captureInCapturedRegion( - CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc, + CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind, bool IsTopScope, Sema &S, bool Invalid) { @@ -18504,16 +18826,12 @@ static bool captureInCapturedRegion( } /// Capture the given variable in the lambda. -static bool captureInLambda(LambdaScopeInfo *LSI, - VarDecl *Var, - SourceLocation Loc, - const bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, +static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var, + SourceLocation Loc, const bool BuildAndDiagnose, + QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, const Sema::TryCaptureKind Kind, - SourceLocation EllipsisLoc, - const bool IsTopScope, + SourceLocation EllipsisLoc, const bool IsTopScope, Sema &S, bool Invalid) { // Determine whether we are capturing by reference or by value. bool ByRef = false; @@ -18523,6 +18841,16 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref); } + BindingDecl *BD = dyn_cast<BindingDecl>(Var); + // FIXME: We should support capturing structured bindings in OpenMP. + if (!Invalid && BD && S.LangOpts.OpenMP) { + if (BuildAndDiagnose) { + S.Diag(Loc, diag::err_capture_binding_openmp) << Var; + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; + } + Invalid = true; + } + // Compute the type of the field that will capture this variable. if (ByRef) { // C++11 [expr.prim.lambda]p15: @@ -18603,7 +18931,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI, return !Invalid; } -static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) { +static bool canCaptureVariableByCopy(ValueDecl *Var, + const ASTContext &Context) { // Offer a Copy fix even if the type is dependent. if (Var->getType()->isDependentType()) return true; @@ -18629,7 +18958,7 @@ static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) { /// standard, for example we can't emit a default copy capture fix-it if we /// already explicitly copy capture capture another variable. static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI, - VarDecl *Var) { + ValueDecl *Var) { assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None); // Don't offer Capture by copy of default capture by copy fixes if Var is // known not to be copy constructible. @@ -18705,14 +19034,20 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI, } bool Sema::tryCaptureVariable( - VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, + ValueDecl *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(); + const auto *VD = dyn_cast<VarDecl>(Var); + if (VD) { + if (VD->isInitCapture()) + VarDC = VarDC->getParent(); + } else { + VD = Var->getPotentiallyDecomposedVarDecl(); + } + assert(VD && "Cannot capture a null variable"); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -18734,12 +19069,14 @@ bool Sema::tryCaptureVariable( // Capture global variables if it is required to use private copy of this // variable. - bool IsGlobal = !Var->hasLocalStorage(); + bool IsGlobal = !VD->hasLocalStorage(); if (IsGlobal && !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true, MaxFunctionScopesIndex))) return true; - Var = Var->getCanonicalDecl(); + + if (isa<VarDecl>(Var)) + Var = cast<VarDecl>(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 @@ -18795,7 +19132,7 @@ bool Sema::tryCaptureVariable( Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl); buildLambdaCaptureFixit(*this, LSI, Var); } else - diagnoseUncapturableValueReference(*this, ExprLoc, Var); + diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var); } return true; } @@ -18943,7 +19280,7 @@ bool Sema::tryCaptureVariable( return Invalid; } -bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, +bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc) { QualType CaptureType; QualType DeclRefType; @@ -18952,7 +19289,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, DeclRefType, nullptr); } -bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { +bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), @@ -18960,7 +19297,7 @@ bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { DeclRefType, nullptr); } -QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { +QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; @@ -19382,6 +19719,38 @@ void Sema::CleanupVarDeclMarking() { "MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?"); } +static void DoMarkPotentialCapture(Sema &SemaRef, SourceLocation Loc, + ValueDecl *Var, Expr *E) { + VarDecl *VD = Var->getPotentiallyDecomposedVarDecl(); + if (!VD) + return; + + const bool RefersToEnclosingScope = + (SemaRef.CurContext != VD->getDeclContext() && + VD->getDeclContext()->isFunctionOrMethod() && VD->hasLocalStorage()); + if (RefersToEnclosingScope) { + LambdaScopeInfo *const LSI = + SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); + if (LSI && (!LSI->CallOperator || + !LSI->CallOperator->Encloses(Var->getDeclContext()))) { + // If a variable could potentially be odr-used, defer marking it so + // until we finish analyzing the full expression for any + // lvalue-to-rvalue + // or discarded value conversions that would obviate odr-use. + // Add it to the list of potential captures that will be analyzed + // later (ActOnFinishFullExpr) for eventual capture and odr-use marking + // unless the variable is a reference that was initialized by a constant + // expression (this will never need to be captured or odr-used). + // + // FIXME: We can simplify this a lot after implementing P0588R1. + assert(E && "Capture variable should be used in an expression."); + if (!Var->getType()->isReferenceType() || + !VD->isUsableInConstantExpressions(SemaRef.Context)) + LSI->addPotentialCapture(E->IgnoreParens()); + } + } +} + static void DoMarkVarDeclReferenced( Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E, llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) { @@ -19505,7 +19874,10 @@ static void DoMarkVarDeclReferenced( switch (OdrUse) { case OdrUseContext::None: - assert((!E || isa<FunctionParmPackExpr>(E)) && + // In some cases, a variable may not have been marked unevaluated, if it + // appears in a defaukt initializer. + assert((!E || isa<FunctionParmPackExpr>(E) || + SemaRef.isUnevaluatedContext()) && "missing non-odr-use marking for unevaluated decl ref"); break; @@ -19528,34 +19900,31 @@ static void DoMarkVarDeclReferenced( // odr-used, but we may still need to track them for lambda capture. // FIXME: Do we also need to do this inside dependent typeid expressions // (which are modeled as unevaluated at this point)? - const bool RefersToEnclosingScope = - (SemaRef.CurContext != Var->getDeclContext() && - Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); - if (RefersToEnclosingScope) { - LambdaScopeInfo *const LSI = - SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); - if (LSI && (!LSI->CallOperator || - !LSI->CallOperator->Encloses(Var->getDeclContext()))) { - // If a variable could potentially be odr-used, defer marking it so - // until we finish analyzing the full expression for any - // lvalue-to-rvalue - // or discarded value conversions that would obviate odr-use. - // Add it to the list of potential captures that will be analyzed - // later (ActOnFinishFullExpr) for eventual capture and odr-use marking - // unless the variable is a reference that was initialized by a constant - // expression (this will never need to be captured or odr-used). - // - // FIXME: We can simplify this a lot after implementing P0588R1. - assert(E && "Capture variable should be used in an expression."); - if (!Var->getType()->isReferenceType() || - !Var->isUsableInConstantExpressions(SemaRef.Context)) - LSI->addPotentialCapture(E->IgnoreParens()); - } - } + DoMarkPotentialCapture(SemaRef, Loc, Var, E); break; } } +static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc, + BindingDecl *BD, Expr *E) { + BD->setReferenced(); + + if (BD->isInvalidDecl()) + return; + + OdrUseContext OdrUse = isOdrUseContext(SemaRef); + if (OdrUse == OdrUseContext::Used) { + QualType CaptureType, DeclRefType; + SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/ true, CaptureType, + DeclRefType, + /*FunctionScopeIndexToStopAt*/ nullptr); + } else if (OdrUse == OdrUseContext::Dependent) { + DoMarkPotentialCapture(SemaRef, Loc, BD, E); + } +} + /// Mark a variable referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be /// used directly for normal expressions referring to VarDecl. @@ -19575,6 +19944,11 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, return; } + if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) { + DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E); + return; + } + SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); // If this is a call to a method via a cast, also mark the method in the @@ -19615,7 +19989,9 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) if (!isUnevaluatedContext() && !isConstantEvaluated() && - FD->isConsteval() && !RebuildingImmediateInvocation) + !isImmediateFunctionContext() && + !isCheckingDefaultArgumentOrInitializer() && FD->isConsteval() && + !RebuildingImmediateInvocation && !FD->isDependentContext()) ExprEvalContexts.back().ReferenceToConsteval.insert(E); MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); @@ -19849,7 +20225,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { return DiagRuntimeBehavior( - Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD); + Loc, Statement ? llvm::ArrayRef(Statement) : std::nullopt, PD); } bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, @@ -20761,7 +21137,8 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { ExprResult Sema::ActOnObjCAvailabilityCheckExpr( llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc, SourceLocation RParen) { - auto FindSpecVersion = [&](StringRef Platform) -> Optional<VersionTuple> { + auto FindSpecVersion = + [&](StringRef Platform) -> std::optional<VersionTuple> { auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) { return Spec.getPlatform() == Platform; }); @@ -20773,7 +21150,7 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( }); } if (Spec == AvailSpecs.end()) - return None; + return std::nullopt; return Spec->getVersion(); }; |