diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp | 4738 |
1 files changed, 3413 insertions, 1325 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp index f04eb9199024..4cce0abc2315 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp @@ -25,18 +25,24 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TypeTraits.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" @@ -48,12 +54,14 @@ #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/TypeSize.h" +#include <optional> using namespace clang; using namespace sema; -using llvm::RoundingMode; /// Determine whether the use of this declaration is valid, without /// emitting diagnostics. @@ -97,7 +105,7 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { // [[maybe_unused]] should not diagnose uses, but __attribute__((unused)) // should diagnose them. if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused && - A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) { + A->getSemanticSpelling() != UnusedAttr::C23_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; @@ -131,7 +139,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; } @@ -165,7 +173,7 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S, return; // Check if the decl has internal linkage. - if (D->getFormalLinkage() != InternalLinkage) + if (D->getFormalLinkage() != Linkage::Internal) return; // Downgrade from ExtWarn to Extension if @@ -217,7 +225,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, @@ -276,9 +285,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; @@ -300,8 +310,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; - if (getLangOpts().SYCLIsDevice && !checkSYCLDeviceFunction(Loc, FD)) - return true; } if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -344,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) @@ -366,10 +375,21 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); - if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) { - if (auto *VD = dyn_cast<ValueDecl>(D)) - checkDeviceDecl(VD, Loc); + if (D->hasAttr<AvailableOnlyInDefaultEvalMethodAttr>()) { + if (getLangOpts().getFPEvalMethod() != + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine && + PP.getLastFPEvalPragmaLocation().isValid() && + PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod()) + Diag(D->getLocation(), + diag::err_type_available_only_in_default_eval_method) + << D->getName(); + } + + if (auto *VD = dyn_cast<ValueDecl>(D)) + checkTypeSupport(VD->getType(), Loc, VD); + if (LangOpts.SYCLIsDevice || + (LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice)) { if (!Context.getTargetInfo().isTLSSupported()) if (const auto *VD = dyn_cast<VarDecl>(D)) if (VD->getTLSKind() != VarDecl::TLS_None) @@ -394,80 +414,83 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, /// message-send is to a declaration with the sentinel attribute, and /// if so, it checks that the requirements of the sentinel are /// satisfied. -void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, +void Sema::DiagnoseSentinelCalls(const NamedDecl *D, SourceLocation Loc, ArrayRef<Expr *> Args) { - const SentinelAttr *attr = D->getAttr<SentinelAttr>(); - if (!attr) + const SentinelAttr *Attr = D->getAttr<SentinelAttr>(); + if (!Attr) return; // The number of formal parameters of the declaration. - unsigned numFormalParams; + unsigned NumFormalParams; // The kind of declaration. This is also an index into a %select in // the diagnostic. - enum CalleeType { CT_Function, CT_Method, CT_Block } calleeType; - - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - numFormalParams = MD->param_size(); - calleeType = CT_Method; - } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - numFormalParams = FD->param_size(); - calleeType = CT_Function; - } else if (isa<VarDecl>(D)) { - QualType type = cast<ValueDecl>(D)->getType(); - const FunctionType *fn = nullptr; - if (const PointerType *ptr = type->getAs<PointerType>()) { - fn = ptr->getPointeeType()->getAs<FunctionType>(); - if (!fn) return; - calleeType = CT_Function; - } else if (const BlockPointerType *ptr = type->getAs<BlockPointerType>()) { - fn = ptr->getPointeeType()->castAs<FunctionType>(); - calleeType = CT_Block; + enum { CK_Function, CK_Method, CK_Block } CalleeKind; + + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + NumFormalParams = MD->param_size(); + CalleeKind = CK_Method; + } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + NumFormalParams = FD->param_size(); + CalleeKind = CK_Function; + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { + QualType Ty = VD->getType(); + const FunctionType *Fn = nullptr; + if (const auto *PtrTy = Ty->getAs<PointerType>()) { + Fn = PtrTy->getPointeeType()->getAs<FunctionType>(); + if (!Fn) + return; + CalleeKind = CK_Function; + } else if (const auto *PtrTy = Ty->getAs<BlockPointerType>()) { + Fn = PtrTy->getPointeeType()->castAs<FunctionType>(); + CalleeKind = CK_Block; } else { return; } - if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fn)) { - numFormalParams = proto->getNumParams(); - } else { - numFormalParams = 0; - } + if (const auto *proto = dyn_cast<FunctionProtoType>(Fn)) + NumFormalParams = proto->getNumParams(); + else + NumFormalParams = 0; } else { return; } - // "nullPos" is the number of formal parameters at the end which + // "NullPos" is the number of formal parameters at the end which // effectively count as part of the variadic arguments. This is // useful if you would prefer to not have *any* formal parameters, // but the language forces you to have at least one. - unsigned nullPos = attr->getNullPos(); - assert((nullPos == 0 || nullPos == 1) && "invalid null position on sentinel"); - numFormalParams = (nullPos > numFormalParams ? 0 : numFormalParams - nullPos); + unsigned NullPos = Attr->getNullPos(); + assert((NullPos == 0 || NullPos == 1) && "invalid null position on sentinel"); + NumFormalParams = (NullPos > NumFormalParams ? 0 : NumFormalParams - NullPos); // The number of arguments which should follow the sentinel. - unsigned numArgsAfterSentinel = attr->getSentinel(); + unsigned NumArgsAfterSentinel = Attr->getSentinel(); // If there aren't enough arguments for all the formal parameters, // the sentinel, and the args after the sentinel, complain. - if (Args.size() < numFormalParams + numArgsAfterSentinel + 1) { + if (Args.size() < NumFormalParams + NumArgsAfterSentinel + 1) { Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType); + Diag(D->getLocation(), diag::note_sentinel_here) << int(CalleeKind); return; } // Otherwise, find the sentinel expression. - Expr *sentinelExpr = Args[Args.size() - numArgsAfterSentinel - 1]; - if (!sentinelExpr) return; - if (sentinelExpr->isValueDependent()) return; - if (Context.isSentinelNullExpr(sentinelExpr)) return; + const Expr *SentinelExpr = Args[Args.size() - NumArgsAfterSentinel - 1]; + if (!SentinelExpr) + return; + if (SentinelExpr->isValueDependent()) + return; + if (Context.isSentinelNullExpr(SentinelExpr)) + return; // Pick a reasonable string to insert. Optimistically use 'nil', 'nullptr', // or 'NULL' if those are actually defined in the context. Only use // 'nil' for ObjC methods, where it's much more likely that the // variadic arguments form a list of object pointers. - SourceLocation MissingNilLoc = getLocForEndOfToken(sentinelExpr->getEndLoc()); + SourceLocation MissingNilLoc = getLocForEndOfToken(SentinelExpr->getEndLoc()); std::string NullValue; - if (calleeType == CT_Method && PP.isMacroDefined("nil")) + if (CalleeKind == CK_Method && PP.isMacroDefined("nil")) NullValue = "nil"; else if (getLangOpts().CPlusPlus11) NullValue = "nullptr"; @@ -477,12 +500,13 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, NullValue = "(void*) 0"; if (MissingNilLoc.isInvalid()) - Diag(Loc, diag::warn_missing_sentinel) << int(calleeType); + Diag(Loc, diag::warn_missing_sentinel) << int(CalleeKind); else Diag(MissingNilLoc, diag::warn_missing_sentinel) - << int(calleeType) - << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue); - Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType); + << int(CalleeKind) + << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue); + Diag(D->getLocation(), diag::note_sentinel_here) + << int(CalleeKind) << Attr->getRange(); } SourceRange Sema::getExprRange(Expr *E) const { @@ -496,7 +520,7 @@ SourceRange Sema::getExprRange(Expr *E) const { /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { // Handle any placeholder expressions which made it here. - if (E->getType()->isPlaceholderType()) { + if (E->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); @@ -620,7 +644,7 @@ static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE, ExprResult Sema::DefaultLvalueConversion(Expr *E) { // Handle any placeholder expressions which made it here. - if (E->getType()->isPlaceholderType()) { + if (E->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); @@ -772,6 +796,40 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); + LangOptions::FPEvalMethodKind EvalMethod = CurFPFeatures.getFPEvalMethod(); + if (EvalMethod != LangOptions::FEM_Source && Ty->isFloatingType() && + (getLangOpts().getFPEvalMethod() != + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine || + PP.getLastFPEvalPragmaLocation().isValid())) { + switch (EvalMethod) { + default: + llvm_unreachable("Unrecognized float evaluation method"); + break; + case LangOptions::FEM_UnsetOnCommandLine: + llvm_unreachable("Float evaluation method should be set by now"); + break; + case LangOptions::FEM_Double: + if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) > 0) + // Widen the expression to double. + return Ty->isComplexType() + ? ImpCastExprToType(E, + Context.getComplexType(Context.DoubleTy), + CK_FloatingComplexCast) + : ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast); + break; + case LangOptions::FEM_Extended: + if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) > 0) + // Widen the expression to long double. + return Ty->isComplexType() + ? ImpCastExprToType( + E, Context.getComplexType(Context.LongDoubleTy), + CK_FloatingComplexCast) + : ImpCastExprToType(E, Context.LongDoubleTy, + CK_FloatingCast); + break; + } + } + // Half FP have to be promoted to float unless it is natively supported if (Ty->isHalfType() && !getLangOpts().NativeHalfType) return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast); @@ -798,7 +856,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; @@ -897,6 +955,11 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) return VAK_Invalid; + if (Context.getTargetInfo().getTriple().isWasm() && + Ty.isWebAssemblyReferenceType()) { + return VAK_Invalid; + } + if (Ty.isCXX98PODType(Context)) return VAK_Valid; @@ -937,7 +1000,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 @@ -1017,7 +1080,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(); @@ -1049,7 +1112,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); @@ -1061,60 +1124,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 @@ -1197,45 +1259,32 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS, /*ConvertInt=*/!IsCompAssign); } -/// Diagnose attempts to convert between __float128 and long double if -/// there is no support for such conversion. Helper function of -/// UsualArithmeticConversions(). +/// Diagnose attempts to convert between __float128, __ibm128 and +/// long double if there is no support for such conversion. +/// Helper function of UsualArithmeticConversions(). static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, QualType RHSType) { - /* No issue converting if at least one of the types is not a floating point - type or the two types have the same rank. - */ - if (!LHSType->isFloatingType() || !RHSType->isFloatingType() || - S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0) + // No issue if either is not a floating point type. + if (!LHSType->isFloatingType() || !RHSType->isFloatingType()) return false; - assert(LHSType->isFloatingType() && RHSType->isFloatingType() && - "The remaining types must be floating point types."); - + // No issue if both have the same 128-bit float semantics. auto *LHSComplex = LHSType->getAs<ComplexType>(); auto *RHSComplex = RHSType->getAs<ComplexType>(); - QualType LHSElemType = LHSComplex ? - LHSComplex->getElementType() : LHSType; - QualType RHSElemType = RHSComplex ? - RHSComplex->getElementType() : RHSType; + QualType LHSElem = LHSComplex ? LHSComplex->getElementType() : LHSType; + QualType RHSElem = RHSComplex ? RHSComplex->getElementType() : RHSType; - // No issue if the two types have the same representation - if (&S.Context.getFloatTypeSemantics(LHSElemType) == - &S.Context.getFloatTypeSemantics(RHSElemType)) - return false; + const llvm::fltSemantics &LHSSem = S.Context.getFloatTypeSemantics(LHSElem); + const llvm::fltSemantics &RHSSem = S.Context.getFloatTypeSemantics(RHSElem); - bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty && - RHSElemType == S.Context.LongDoubleTy); - Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && - RHSElemType == S.Context.Float128Ty); + if ((&LHSSem != &llvm::APFloat::PPCDoubleDouble() || + &RHSSem != &llvm::APFloat::IEEEquad()) && + (&LHSSem != &llvm::APFloat::IEEEquad() || + &RHSSem != &llvm::APFloat::PPCDoubleDouble())) + return false; - // We've handled the situation where __float128 and long double have the same - // representation. We allow all conversions for all possible long double types - // except PPC's double double. - return Float128AndLongDouble && - (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == - &llvm::APFloat::PPCDoubleDouble()); + return true; } typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); @@ -1454,16 +1503,22 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS, bool IsCompAssign = ACK == Sema::ACK_CompAssign; if ((!IsCompAssign && LEnum && R->isFloatingType()) || (REnum && L->isFloatingType())) { - S.Diag(Loc, S.getLangOpts().CPlusPlus20 + S.Diag(Loc, S.getLangOpts().CPlusPlus26 + ? diag::err_arith_conv_enum_float_cxx26 + : S.getLangOpts().CPlusPlus20 ? diag::warn_arith_conv_enum_float_cxx20 : diag::warn_arith_conv_enum_float) - << LHS->getSourceRange() << RHS->getSourceRange() - << (int)ACK << LEnum << L << R; + << LHS->getSourceRange() << RHS->getSourceRange() << (int)ACK << LEnum + << L << R; } else if (!IsCompAssign && LEnum && REnum && !S.Context.hasSameUnqualifiedType(L, R)) { unsigned DiagID; - if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() || - !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) { + // In C++ 26, usual arithmetic conversions between 2 different enum types + // are ill-formed. + if (S.getLangOpts().CPlusPlus26) + DiagID = diag::err_conv_mixed_enum_types_cxx26; + else if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() || + !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) { // If either enumeration type is unnamed, it's less likely that the // user cares about this, but this situation is still deprecated in // C++2a. Use a different warning group. @@ -1513,18 +1568,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). @@ -1533,7 +1586,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()) @@ -1542,20 +1595,20 @@ 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. - // Diagnose attempts to convert between __float128 and long double where - // such conversions currently can't be handled. + // Diagnose attempts to convert between __ibm128, __float128 and long double + // where such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return QualType(); // 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()) @@ -1580,13 +1633,10 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, //===----------------------------------------------------------------------===// -ExprResult -Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, - SourceLocation DefaultLoc, - SourceLocation RParenLoc, - Expr *ControllingExpr, - ArrayRef<ParsedType> ArgTypes, - ArrayRef<Expr *> ArgExprs) { +ExprResult Sema::ActOnGenericSelectionExpr( + SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool PredicateIsExpr, void *ControllingExprOrType, + ArrayRef<ParsedType> ArgTypes, ArrayRef<Expr *> ArgExprs) { unsigned NumAssocs = ArgTypes.size(); assert(NumAssocs == ArgExprs.size()); @@ -1598,47 +1648,68 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, Types[i] = nullptr; } - ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, - ControllingExpr, - llvm::makeArrayRef(Types, NumAssocs), - ArgExprs); + // If we have a controlling type, we need to convert it from a parsed type + // into a semantic type and then pass that along. + if (!PredicateIsExpr) { + TypeSourceInfo *ControllingType; + (void)GetTypeFromParser(ParsedType::getFromOpaquePtr(ControllingExprOrType), + &ControllingType); + assert(ControllingType && "couldn't get the type out of the parser"); + ControllingExprOrType = ControllingType; + } + + ExprResult ER = CreateGenericSelectionExpr( + KeyLoc, DefaultLoc, RParenLoc, PredicateIsExpr, ControllingExprOrType, + llvm::ArrayRef(Types, NumAssocs), ArgExprs); delete [] Types; return ER; } -ExprResult -Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, - SourceLocation DefaultLoc, - SourceLocation RParenLoc, - Expr *ControllingExpr, - ArrayRef<TypeSourceInfo *> Types, - ArrayRef<Expr *> Exprs) { +ExprResult Sema::CreateGenericSelectionExpr( + SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool PredicateIsExpr, void *ControllingExprOrType, + ArrayRef<TypeSourceInfo *> Types, ArrayRef<Expr *> Exprs) { unsigned NumAssocs = Types.size(); assert(NumAssocs == Exprs.size()); - - // Decay and strip qualifiers for the controlling expression type, and handle - // placeholder type replacement. See committee discussion from WG14 DR423. - { + assert(ControllingExprOrType && + "Must have either a controlling expression or a controlling type"); + + Expr *ControllingExpr = nullptr; + TypeSourceInfo *ControllingType = nullptr; + if (PredicateIsExpr) { + // Decay and strip qualifiers for the controlling expression type, and + // handle placeholder type replacement. See committee discussion from WG14 + // DR423. EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult R = DefaultFunctionArrayLvalueConversion(ControllingExpr); + ExprResult R = DefaultFunctionArrayLvalueConversion( + reinterpret_cast<Expr *>(ControllingExprOrType)); if (R.isInvalid()) return ExprError(); ControllingExpr = R.get(); + } else { + // The extension form uses the type directly rather than converting it. + ControllingType = reinterpret_cast<TypeSourceInfo *>(ControllingExprOrType); + if (!ControllingType) + return ExprError(); } + bool TypeErrorFound = false, + IsResultDependent = ControllingExpr + ? ControllingExpr->isTypeDependent() + : ControllingType->getType()->isDependentType(), + ContainsUnexpandedParameterPack = + ControllingExpr + ? ControllingExpr->containsUnexpandedParameterPack() + : ControllingType->getType()->containsUnexpandedParameterPack(); + // The controlling expression is an unevaluated operand, so side effects are // likely unintended. - if (!inTemplateInstantiation() && + if (!inTemplateInstantiation() && !IsResultDependent && ControllingExpr && ControllingExpr->HasSideEffects(Context, false)) Diag(ControllingExpr->getExprLoc(), diag::warn_side_effects_unevaluated_context); - bool TypeErrorFound = false, - IsResultDependent = ControllingExpr->isTypeDependent(), - ContainsUnexpandedParameterPack - = ControllingExpr->containsUnexpandedParameterPack(); - for (unsigned i = 0; i < NumAssocs; ++i) { if (Exprs[i]->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; @@ -1650,15 +1721,55 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, if (Types[i]->getType()->isDependentType()) { IsResultDependent = true; } else { + // We relax the restriction on use of incomplete types and non-object + // types with the type-based extension of _Generic. Allowing incomplete + // objects means those can be used as "tags" for a type-safe way to map + // to a value. Similarly, matching on function types rather than + // function pointer types can be useful. However, the restriction on VM + // types makes sense to retain as there are open questions about how + // the selection can be made at compile time. + // // C11 6.5.1.1p2 "The type name in a generic association shall specify a // complete object type other than a variably modified type." unsigned D = 0; - if (Types[i]->getType()->isIncompleteType()) + if (ControllingExpr && Types[i]->getType()->isIncompleteType()) D = diag::err_assoc_type_incomplete; - else if (!Types[i]->getType()->isObjectType()) + else if (ControllingExpr && !Types[i]->getType()->isObjectType()) D = diag::err_assoc_type_nonobject; else if (Types[i]->getType()->isVariablyModifiedType()) D = diag::err_assoc_type_variably_modified; + else if (ControllingExpr) { + // Because the controlling expression undergoes lvalue conversion, + // array conversion, and function conversion, an association which is + // of array type, function type, or is qualified can never be + // reached. We will warn about this so users are less surprised by + // the unreachable association. However, we don't have to handle + // function types; that's not an object type, so it's handled above. + // + // The logic is somewhat different for C++ because C++ has different + // lvalue to rvalue conversion rules than C. [conv.lvalue]p1 says, + // If T is a non-class type, the type of the prvalue is the cv- + // unqualified version of T. Otherwise, the type of the prvalue is T. + // The result of these rules is that all qualified types in an + // association in C are unreachable, and in C++, only qualified non- + // class types are unreachable. + // + // NB: this does not apply when the first operand is a type rather + // than an expression, because the type form does not undergo + // conversion. + unsigned Reason = 0; + QualType QT = Types[i]->getType(); + if (QT->isArrayType()) + Reason = 1; + else if (QT.hasQualifiers() && + (!LangOpts.CPlusPlus || !QT->isRecordType())) + Reason = 2; + + if (Reason) + Diag(Types[i]->getTypeLoc().getBeginLoc(), + diag::warn_unreachable_association) + << QT << (Reason - 1); + } if (D != 0) { Diag(Types[i]->getTypeLoc().getBeginLoc(), D) @@ -1692,31 +1803,60 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // If we determined that the generic selection is result-dependent, don't // try to compute the result expression. - if (IsResultDependent) - return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, Types, + if (IsResultDependent) { + if (ControllingExpr) + return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, + Types, Exprs, DefaultLoc, RParenLoc, + ContainsUnexpandedParameterPack); + return GenericSelectionExpr::Create(Context, KeyLoc, ControllingType, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack); + } SmallVector<unsigned, 1> CompatIndices; unsigned DefaultIndex = -1U; + // Look at the canonical type of the controlling expression in case it was a + // deduced type like __auto_type. However, when issuing diagnostics, use the + // type the user wrote in source rather than the canonical one. for (unsigned i = 0; i < NumAssocs; ++i) { if (!Types[i]) DefaultIndex = i; - else if (Context.typesAreCompatible(ControllingExpr->getType(), - Types[i]->getType())) + else if (ControllingExpr && + Context.typesAreCompatible( + ControllingExpr->getType().getCanonicalType(), + Types[i]->getType())) + CompatIndices.push_back(i); + else if (ControllingType && + Context.typesAreCompatible( + ControllingType->getType().getCanonicalType(), + Types[i]->getType())) CompatIndices.push_back(i); } + auto GetControllingRangeAndType = [](Expr *ControllingExpr, + TypeSourceInfo *ControllingType) { + // We strip parens here because the controlling expression is typically + // parenthesized in macro definitions. + if (ControllingExpr) + ControllingExpr = ControllingExpr->IgnoreParens(); + + SourceRange SR = ControllingExpr + ? ControllingExpr->getSourceRange() + : ControllingType->getTypeLoc().getSourceRange(); + QualType QT = ControllingExpr ? ControllingExpr->getType() + : ControllingType->getType(); + + return std::make_pair(SR, QT); + }; + // C11 6.5.1.1p2 "The controlling expression of a generic selection shall have // type compatible with at most one of the types named in its generic // association list." if (CompatIndices.size() > 1) { - // We strip parens here because the controlling expression is typically - // parenthesized in macro definitions. - ControllingExpr = ControllingExpr->IgnoreParens(); - Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_multi_match) - << ControllingExpr->getSourceRange() << ControllingExpr->getType() - << (unsigned)CompatIndices.size(); + auto P = GetControllingRangeAndType(ControllingExpr, ControllingType); + SourceRange SR = P.first; + Diag(SR.getBegin(), diag::err_generic_sel_multi_match) + << SR << P.second << (unsigned)CompatIndices.size(); for (unsigned I : CompatIndices) { Diag(Types[I]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc) @@ -1730,11 +1870,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // its controlling expression shall have type compatible with exactly one of // the types named in its generic association list." if (DefaultIndex == -1U && CompatIndices.size() == 0) { - // We strip parens here because the controlling expression is typically - // parenthesized in macro definitions. - ControllingExpr = ControllingExpr->IgnoreParens(); - Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_no_match) - << ControllingExpr->getSourceRange() << ControllingExpr->getType(); + auto P = GetControllingRangeAndType(ControllingExpr, ControllingType); + SourceRange SR = P.first; + Diag(SR.getBegin(), diag::err_generic_sel_no_match) << SR << P.second; return ExprError(); } @@ -1746,11 +1884,46 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, unsigned ResultIndex = CompatIndices.size() ? CompatIndices[0] : DefaultIndex; + if (ControllingExpr) { + return GenericSelectionExpr::Create( + Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, + ContainsUnexpandedParameterPack, ResultIndex); + } return GenericSelectionExpr::Create( - Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, + Context, KeyLoc, ControllingType, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack, ResultIndex); } +static PredefinedIdentKind getPredefinedExprKind(tok::TokenKind Kind) { + switch (Kind) { + default: + llvm_unreachable("unexpected TokenKind"); + case tok::kw___func__: + return PredefinedIdentKind::Func; // [C99 6.4.2.2] + case tok::kw___FUNCTION__: + return PredefinedIdentKind::Function; + case tok::kw___FUNCDNAME__: + return PredefinedIdentKind::FuncDName; // [MS] + case tok::kw___FUNCSIG__: + return PredefinedIdentKind::FuncSig; // [MS] + case tok::kw_L__FUNCTION__: + return PredefinedIdentKind::LFunction; // [MS] + case tok::kw_L__FUNCSIG__: + return PredefinedIdentKind::LFuncSig; // [MS] + case tok::kw___PRETTY_FUNCTION__: + return PredefinedIdentKind::PrettyFunction; // [GNU] + } +} + +/// getPredefinedExprDecl - Returns Decl of a given DeclContext that can be used +/// to determine the value of a PredefinedExpr. This can be either a +/// block, lambda, captured statement, function, otherwise a nullptr. +static Decl *getPredefinedExprDecl(DeclContext *DC) { + while (DC && !isa<BlockDecl, CapturedDecl, FunctionDecl, ObjCMethodDecl>(DC)) + DC = DC->getParent(); + return cast_or_null<Decl>(DC); +} + /// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the /// location of the token and the offset of the ud-suffix within it. static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc, @@ -1781,7 +1954,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) @@ -1790,6 +1963,84 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); } +ExprResult Sema::ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks) { + // StringToks needs backing storage as it doesn't hold array elements itself + std::vector<Token> ExpandedToks; + if (getLangOpts().MicrosoftExt) + StringToks = ExpandedToks = ExpandFunctionLocalPredefinedMacros(StringToks); + + StringLiteralParser Literal(StringToks, PP, + StringLiteralEvalMethod::Unevaluated); + if (Literal.hadError) + return ExprError(); + + SmallVector<SourceLocation, 4> StringTokLocs; + for (const Token &Tok : StringToks) + StringTokLocs.push_back(Tok.getLocation()); + + StringLiteral *Lit = StringLiteral::Create( + Context, Literal.GetString(), StringLiteralKind::Unevaluated, false, {}, + &StringTokLocs[0], StringTokLocs.size()); + + if (!Literal.getUDSuffix().empty()) { + SourceLocation UDSuffixLoc = + getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()], + Literal.getUDSuffixOffset()); + return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl)); + } + + return Lit; +} + +std::vector<Token> +Sema::ExpandFunctionLocalPredefinedMacros(ArrayRef<Token> Toks) { + // MSVC treats some predefined identifiers (e.g. __FUNCTION__) as function + // local macros that expand to string literals that may be concatenated. + // These macros are expanded here (in Sema), because StringLiteralParser + // (in Lex) doesn't know the enclosing function (because it hasn't been + // parsed yet). + assert(getLangOpts().MicrosoftExt); + + // Note: Although function local macros are defined only inside functions, + // we ensure a valid `CurrentDecl` even outside of a function. This allows + // expansion of macros into empty string literals without additional checks. + Decl *CurrentDecl = getPredefinedExprDecl(CurContext); + if (!CurrentDecl) + CurrentDecl = Context.getTranslationUnitDecl(); + + std::vector<Token> ExpandedToks; + ExpandedToks.reserve(Toks.size()); + for (const Token &Tok : Toks) { + if (!isFunctionLocalStringLiteralMacro(Tok.getKind(), getLangOpts())) { + assert(tok::isStringLiteral(Tok.getKind())); + ExpandedToks.emplace_back(Tok); + continue; + } + if (isa<TranslationUnitDecl>(CurrentDecl)) + Diag(Tok.getLocation(), diag::ext_predef_outside_function); + // Stringify predefined expression + Diag(Tok.getLocation(), diag::ext_string_literal_from_predefined) + << Tok.getKind(); + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + Token &Exp = ExpandedToks.emplace_back(); + Exp.startToken(); + if (Tok.getKind() == tok::kw_L__FUNCTION__ || + Tok.getKind() == tok::kw_L__FUNCSIG__) { + OS << 'L'; + Exp.setKind(tok::wide_string_literal); + } else { + Exp.setKind(tok::string_literal); + } + OS << '"' + << Lexer::Stringify(PredefinedExpr::ComputeName( + getPredefinedExprKind(Tok.getKind()), CurrentDecl)) + << '"'; + PP.CreateString(OS.str(), Exp, Tok.getLocation(), Tok.getEndLoc()); + } + return ExpandedToks; +} + /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string /// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from @@ -1800,6 +2051,11 @@ ExprResult Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { assert(!StringToks.empty() && "Must have at least one string!"); + // StringToks needs backing storage as it doesn't hold array elements itself + std::vector<Token> ExpandedToks; + if (getLangOpts().MicrosoftExt) + StringToks = ExpandedToks = ExpandFunctionLocalPredefinedMacros(StringToks); + StringLiteralParser Literal(StringToks, PP); if (Literal.hadError) return ExprError(); @@ -1809,20 +2065,20 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { StringTokLocs.push_back(Tok.getLocation()); QualType CharTy = Context.CharTy; - StringLiteral::StringKind Kind = StringLiteral::Ascii; + StringLiteralKind Kind = StringLiteralKind::Ordinary; if (Literal.isWide()) { CharTy = Context.getWideCharType(); - Kind = StringLiteral::Wide; + Kind = StringLiteralKind::Wide; } else if (Literal.isUTF8()) { if (getLangOpts().Char8) CharTy = Context.Char8Ty; - Kind = StringLiteral::UTF8; + Kind = StringLiteralKind::UTF8; } else if (Literal.isUTF16()) { CharTy = Context.Char16Ty; - Kind = StringLiteral::UTF16; + Kind = StringLiteralKind::UTF16; } else if (Literal.isUTF32()) { CharTy = Context.Char32Ty; - Kind = StringLiteral::UTF32; + Kind = StringLiteralKind::UTF32; } else if (Literal.isPascal()) { CharTy = Context.UnsignedCharTy; } @@ -1830,7 +2086,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { // Warn on initializing an array of char from a u8 string literal; this // becomes ill-formed in C++2a. if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus20 && - !getLangOpts().Char8 && Kind == StringLiteral::UTF8) { + !getLangOpts().Char8 && Kind == StringLiteralKind::UTF8) { Diag(StringTokLocs.front(), diag::warn_cxx20_compat_utf8_string); // Create removals for all 'u8' prefixes in the string literal(s). This @@ -1906,8 +2162,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: { @@ -1927,8 +2183,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: @@ -2024,9 +2280,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, @@ -2045,9 +2300,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, // b) if the function is a defaulted comparison, we can use the body we // build when defining it as input to the exception specification // computation rather than computing a new body. - if (auto *FPT = Ty->getAs<FunctionProtoType>()) { + if (const auto *FPT = Ty->getAs<FunctionProtoType>()) { if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { - if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) + if (const auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers())); } } @@ -2057,8 +2312,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc())) getCurFunction()->recordUseOfWeak(E); - FieldDecl *FD = dyn_cast<FieldDecl>(D); - if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D)) + const auto *FD = dyn_cast<FieldDecl>(D); + if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) FD = IFD->getAnonField(); if (FD) { UnusedPrivateFields.remove(FD); @@ -2069,8 +2324,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier // designates a bit-field. - if (auto *BD = dyn_cast<BindingDecl>(D)) - if (auto *BE = BD->getBinding()) + if (const auto *BD = dyn_cast<BindingDecl>(D)) + if (const auto *BE = BD->getBinding()) E->setObjectKind(BE->getObjectKind()); return E; @@ -2149,7 +2404,7 @@ static void emitEmptyLookupTypoDiagnostic( /// /// Return \c true if the error is unrecoverable, or \c false if the caller /// should attempt to recover using these lookup results. -bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { +bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) { // During a default argument instantiation the CurContext points // to a CXXMethodDecl; but we can't apply a this-> fixit inside a // function parameter list, hence add an explicit check. @@ -2157,7 +2412,7 @@ bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { !CodeSynthesisContexts.empty() && CodeSynthesisContexts.back().Kind == CodeSynthesisContext::DefaultFunctionArgumentInstantiation; - CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); + const auto *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); bool isInstance = CurMethod && CurMethod->isInstance() && R.getNamingClass() == CurMethod->getParent() && !isDefaultArgument; @@ -2189,7 +2444,7 @@ bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { Diag(R.getNameLoc(), DiagID) << R.getLookupName(); } - for (NamedDecl *D : R) + for (const NamedDecl *D : R) Diag(D->getLocation(), NoteID); // Return true if we are inside a default argument instantiation @@ -2200,7 +2455,7 @@ bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { // FIXME: Is this special case necessary? We could allow the caller to // diagnose this. if (isDefaultArgument && ((*R.begin())->isCXXInstanceMember())) { - Diag(R.getNameLoc(), diag::err_member_call_without_object); + Diag(R.getNameLoc(), diag::err_member_call_without_object) << 0; return true; } @@ -2214,7 +2469,8 @@ bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args, TypoExpr **Out) { + ArrayRef<Expr *> Args, DeclContext *LookupCtx, + TypoExpr **Out) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -2230,7 +2486,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // unqualified lookup. This is useful when (for example) the // original lookup would not have found something because it was a // dependent name. - DeclContext *DC = SS.isEmpty() ? CurContext : nullptr; + DeclContext *DC = + LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr); while (DC) { if (isa<CXXRecordDecl>(DC)) { LookupQualifiedName(R, DC); @@ -2273,12 +2530,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, diagnostic, diagnostic_suggest); }, - nullptr, CTK_ErrorRecovery); + nullptr, CTK_ErrorRecovery, LookupCtx); if (*Out) return true; - } else if (S && - (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), - S, &SS, CCC, CTK_ErrorRecovery))) { + } else if (S && (Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, + &SS, CCC, CTK_ErrorRecovery, LookupCtx))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; @@ -2527,9 +2784,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, if (R.isAmbiguous()) return ExprError(); - // This could be an implicitly declared function reference (legal in C90, - // extension in C99, forbidden in C++). - if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus) { + // This could be an implicitly declared function reference if the language + // mode allows it as a feature. + if (R.empty() && HasTrailingLParen && II && + getLangOpts().implicitFunctionsAllowed()) { NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S); if (D) R.addDecl(D); } @@ -2567,7 +2825,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, nullptr, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); @@ -2679,6 +2937,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(), @@ -2735,7 +2997,7 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr( TypeLocBuilder TLB; TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc()); - QualType ET = getElaboratedType(ETK_None, SS, Ty); + QualType ET = getElaboratedType(ElaboratedTypeKeyword::None, SS, Ty); ElaboratedTypeLoc QTL = TLB.push<ElaboratedTypeLoc>(ET); QTL.setElaboratedKeywordLoc(SourceLocation()); QTL.setQualifierLoc(SS.getWithLocInContext(Context)); @@ -2888,7 +3150,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}); @@ -2942,7 +3204,7 @@ Sema::PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member) { - CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); + const auto *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); if (!RD) return From; @@ -2967,12 +3229,12 @@ Sema::PerformObjectMemberConversion(Expr *From, DestType = DestRecordType; FromRecordType = FromType; } - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) { - if (Method->isStatic()) + } else if (const auto *Method = dyn_cast<CXXMethodDecl>(Member)) { + if (!Method->isImplicitObjectMemberFunction()) return From; - DestType = Method->getThisType(); - DestRecordType = DestType->getPointeeType(); + DestType = Method->getThisType().getNonReferenceType(); + DestRecordType = Method->getFunctionObjectParameterType(); if (FromType->getAs<PointerType>()) { FromRecordType = FromType->getPointeeType(); @@ -3034,7 +3296,7 @@ Sema::PerformObjectMemberConversion(Expr *From, QualType QType = QualType(Qualifier->getAsType(), 0); assert(QType->isRecordType() && "lookup done with non-record type"); - QualType QRecordType = QualType(QType->getAs<RecordType>(), 0); + QualType QRecordType = QualType(QType->castAs<RecordType>(), 0); // In C++98, the qualifier type doesn't actually have to be a base // type of the object type, in which case we just ignore it. @@ -3087,7 +3349,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // Turn off ADL when we find certain kinds of declarations during // normal lookup: - for (NamedDecl *D : R) { + for (const NamedDecl *D : R) { // C++0x [basic.lookup.argdep]p3: // -- a declaration of a class member // Since using decls preserve this property, we check this on the @@ -3110,9 +3372,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // -- a declaration that is neither a function or a function // template // And also for builtin functions. - if (isa<FunctionDecl>(D)) { - FunctionDecl *FDecl = cast<FunctionDecl>(D); - + if (const auto *FDecl = dyn_cast<FunctionDecl>(D)) { // But also builtin functions. if (FDecl->getBuiltinID() && FDecl->isImplicit()) return false; @@ -3128,8 +3388,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)) { @@ -3175,7 +3436,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 @@ -3193,9 +3455,9 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ULE; } -static void -diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var, DeclContext *DC); +static void diagnoseUncapturableValueReferenceOrBinding(Sema &S, + SourceLocation loc, + ValueDecl *var); /// Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( @@ -3207,8 +3469,12 @@ ExprResult Sema::BuildDeclarationNameExpr( "Cannot refer unambiguously to a function template"); SourceLocation Loc = NameInfo.getLoc(); - if (CheckDeclInExpr(*this, Loc, D)) - return ExprError(); + 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. + return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}); + } if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { // Specifically diagnose references to class templates that are missing @@ -3219,8 +3485,7 @@ ExprResult Sema::BuildDeclarationNameExpr( // Make sure that we're referring to a value. if (!isa<ValueDecl, UnresolvedUsingIfExistsDecl>(D)) { - Diag(Loc, diag::err_ref_non_value) - << D << SS.getRange(); + Diag(Loc, diag::err_ref_non_value) << D << SS.getRange(); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); } @@ -3241,215 +3506,211 @@ ExprResult Sema::BuildDeclarationNameExpr( // Handle members of anonymous structs and unions. If we got here, // and the reference is to a class member indirect field, then this // must be the subject of a pointer-to-member expression. - if (IndirectFieldDecl *indirectField = dyn_cast<IndirectFieldDecl>(VD)) - if (!indirectField->isCXXClassMember()) - return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), - indirectField); + if (auto *IndirectField = dyn_cast<IndirectFieldDecl>(VD); + IndirectField && !IndirectField->isCXXClassMember()) + return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), + IndirectField); - { - QualType type = VD->getType(); - if (type.isNull()) - return ExprError(); - ExprValueKind valueKind = VK_PRValue; + QualType type = VD->getType(); + if (type.isNull()) + return ExprError(); + ExprValueKind valueKind = VK_PRValue; - // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of - // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value, - // is expanded by some outer '...' in the context of the use. - type = type.getNonPackExpansionType(); + // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of + // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value, + // is expanded by some outer '...' in the context of the use. + type = type.getNonPackExpansionType(); - switch (D->getKind()) { + switch (D->getKind()) { // Ignore all the non-ValueDecl kinds. #define ABSTRACT_DECL(kind) #define VALUE(type, base) -#define DECL(type, base) \ - case Decl::type: +#define DECL(type, base) case Decl::type: #include "clang/AST/DeclNodes.inc" - llvm_unreachable("invalid value decl kind"); - - // These shouldn't make it here. - case Decl::ObjCAtDefsField: - llvm_unreachable("forming non-member reference to ivar?"); - - // Enum constants are always r-values and never references. - // Unresolved using declarations are dependent. - case Decl::EnumConstant: - case Decl::UnresolvedUsingValue: - case Decl::OMPDeclareReduction: - case Decl::OMPDeclareMapper: - valueKind = VK_PRValue; + llvm_unreachable("invalid value decl kind"); + + // These shouldn't make it here. + case Decl::ObjCAtDefsField: + llvm_unreachable("forming non-member reference to ivar?"); + + // Enum constants are always r-values and never references. + // Unresolved using declarations are dependent. + case Decl::EnumConstant: + case Decl::UnresolvedUsingValue: + case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: + valueKind = VK_PRValue; + break; + + // Fields and indirect fields that got here must be for + // pointer-to-member expressions; we just call them l-values for + // internal consistency, because this subexpression doesn't really + // exist in the high-level semantics. + case Decl::Field: + case Decl::IndirectField: + case Decl::ObjCIvar: + assert(getLangOpts().CPlusPlus && "building reference to field in C?"); + + // These can't have reference type in well-formed programs, but + // for internal consistency we do this anyway. + type = type.getNonReferenceType(); + valueKind = VK_LValue; + break; + + // Non-type template parameters are either l-values or r-values + // depending on the type. + case Decl::NonTypeTemplateParm: { + if (const ReferenceType *reftype = type->getAs<ReferenceType>()) { + type = reftype->getPointeeType(); + valueKind = VK_LValue; // even if the parameter is an r-value reference break; + } - // Fields and indirect fields that got here must be for - // pointer-to-member expressions; we just call them l-values for - // internal consistency, because this subexpression doesn't really - // exist in the high-level semantics. - case Decl::Field: - case Decl::IndirectField: - case Decl::ObjCIvar: - assert(getLangOpts().CPlusPlus && - "building reference to field in C?"); - - // These can't have reference type in well-formed programs, but - // for internal consistency we do this anyway. - type = type.getNonReferenceType(); + // [expr.prim.id.unqual]p2: + // If the entity is a template parameter object for a template + // parameter of type T, the type of the expression is const T. + // [...] The expression is an lvalue if the entity is a [...] template + // parameter object. + if (type->isRecordType()) { + type = type.getUnqualifiedType().withConst(); valueKind = VK_LValue; break; + } - // Non-type template parameters are either l-values or r-values - // depending on the type. - case Decl::NonTypeTemplateParm: { - if (const ReferenceType *reftype = type->getAs<ReferenceType>()) { - type = reftype->getPointeeType(); - valueKind = VK_LValue; // even if the parameter is an r-value reference - break; - } - - // [expr.prim.id.unqual]p2: - // If the entity is a template parameter object for a template - // parameter of type T, the type of the expression is const T. - // [...] The expression is an lvalue if the entity is a [...] template - // parameter object. - if (type->isRecordType()) { - type = type.getUnqualifiedType().withConst(); - valueKind = VK_LValue; - break; - } + // For non-references, we need to strip qualifiers just in case + // the template parameter was declared as 'const int' or whatever. + valueKind = VK_PRValue; + type = type.getUnqualifiedType(); + break; + } - // For non-references, we need to strip qualifiers just in case - // the template parameter was declared as 'const int' or whatever. + case Decl::Var: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: + case Decl::Decomposition: + case Decl::OMPCapturedExpr: + // In C, "extern void blah;" is valid and is an r-value. + if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && + type->isVoidType()) { valueKind = VK_PRValue; - type = type.getUnqualifiedType(); break; } + [[fallthrough]]; - case Decl::Var: - case Decl::VarTemplateSpecialization: - case Decl::VarTemplatePartialSpecialization: - case Decl::Decomposition: - case Decl::OMPCapturedExpr: - // In C, "extern void blah;" is valid and is an r-value. - if (!getLangOpts().CPlusPlus && - !type.hasQualifiers() && - type->isVoidType()) { - valueKind = VK_PRValue; - break; - } - LLVM_FALLTHROUGH; + case Decl::ImplicitParam: + case Decl::ParmVar: { + // These are always l-values. + valueKind = VK_LValue; + type = type.getNonReferenceType(); - case Decl::ImplicitParam: - case Decl::ParmVar: { - // These are always l-values. - valueKind = VK_LValue; - type = type.getNonReferenceType(); - - // FIXME: Does the addition of const really only apply in - // potentially-evaluated contexts? Since the variable isn't actually - // captured in an unevaluated context, it seems that the answer is no. - if (!isUnevaluatedContext()) { - QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc); - if (!CapturedType.isNull()) - type = CapturedType; - } - - break; + // FIXME: Does the addition of const really only apply in + // potentially-evaluated contexts? Since the variable isn't actually + // captured in an unevaluated context, it seems that the answer is no. + if (!isUnevaluatedContext()) { + QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc); + if (!CapturedType.isNull()) + type = CapturedType; } - 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, CurContext); - } - break; - } - - case Decl::Function: { - if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) { - if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) { - type = Context.BuiltinFnTy; - valueKind = VK_PRValue; - break; - } - } + break; + } - const FunctionType *fty = type->castAs<FunctionType>(); + case Decl::Binding: + // These are always lvalues. + valueKind = VK_LValue; + type = type.getNonReferenceType(); + break; - // If we're referring to a function with an __unknown_anytype - // result type, make the entire expression __unknown_anytype. - if (fty->getReturnType() == Context.UnknownAnyTy) { - type = Context.UnknownAnyTy; + case Decl::Function: { + if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) { + if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) { + type = Context.BuiltinFnTy; valueKind = VK_PRValue; break; } + } - // Functions are l-values in C++. - if (getLangOpts().CPlusPlus) { - valueKind = VK_LValue; - break; - } + const FunctionType *fty = type->castAs<FunctionType>(); - // C99 DR 316 says that, if a function type comes from a - // function definition (without a prototype), that type is only - // used for checking compatibility. Therefore, when referencing - // the function, we pretend that we don't have the full function - // type. - if (!cast<FunctionDecl>(VD)->hasPrototype() && - isa<FunctionProtoType>(fty)) - type = Context.getFunctionNoProtoType(fty->getReturnType(), - fty->getExtInfo()); - - // Functions are r-values in C. + // If we're referring to a function with an __unknown_anytype + // result type, make the entire expression __unknown_anytype. + if (fty->getReturnType() == Context.UnknownAnyTy) { + type = Context.UnknownAnyTy; valueKind = VK_PRValue; break; } - case Decl::CXXDeductionGuide: - llvm_unreachable("building reference to deduction guide"); - - case Decl::MSProperty: - case Decl::MSGuid: - case Decl::TemplateParamObject: - // FIXME: Should MSGuidDecl and template parameter objects be subject to - // capture in OpenMP, or duplicated between host and device? + // Functions are l-values in C++. + if (getLangOpts().CPlusPlus) { valueKind = VK_LValue; break; + } - case Decl::CXXMethod: - // If we're referring to a method with an __unknown_anytype - // result type, make the entire expression __unknown_anytype. - // This should only be possible with a type written directly. - if (const FunctionProtoType *proto - = dyn_cast<FunctionProtoType>(VD->getType())) - if (proto->getReturnType() == Context.UnknownAnyTy) { - type = Context.UnknownAnyTy; - valueKind = VK_PRValue; - break; - } + // C99 DR 316 says that, if a function type comes from a + // function definition (without a prototype), that type is only + // used for checking compatibility. Therefore, when referencing + // the function, we pretend that we don't have the full function + // type. + if (!cast<FunctionDecl>(VD)->hasPrototype() && isa<FunctionProtoType>(fty)) + type = Context.getFunctionNoProtoType(fty->getReturnType(), + fty->getExtInfo()); + + // Functions are r-values in C. + valueKind = VK_PRValue; + break; + } + + case Decl::CXXDeductionGuide: + llvm_unreachable("building reference to deduction guide"); - // C++ methods are l-values if static, r-values if non-static. - if (cast<CXXMethodDecl>(VD)->isStatic()) { - valueKind = VK_LValue; + case Decl::MSProperty: + case Decl::MSGuid: + case Decl::TemplateParamObject: + // FIXME: Should MSGuidDecl and template parameter objects be subject to + // capture in OpenMP, or duplicated between host and device? + valueKind = VK_LValue; + break; + + case Decl::UnnamedGlobalConstant: + valueKind = VK_LValue; + break; + + case Decl::CXXMethod: + // If we're referring to a method with an __unknown_anytype + // result type, make the entire expression __unknown_anytype. + // This should only be possible with a type written directly. + if (const FunctionProtoType *proto = + dyn_cast<FunctionProtoType>(VD->getType())) + if (proto->getReturnType() == Context.UnknownAnyTy) { + type = Context.UnknownAnyTy; + valueKind = VK_PRValue; break; } - LLVM_FALLTHROUGH; - case Decl::CXXConversion: - case Decl::CXXDestructor: - case Decl::CXXConstructor: - valueKind = VK_PRValue; + // C++ methods are l-values if static, r-values if non-static. + if (cast<CXXMethodDecl>(VD)->isStatic()) { + valueKind = VK_LValue; break; } + [[fallthrough]]; - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, - /*FIXME: TemplateKWLoc*/ SourceLocation(), - TemplateArgs); + case Decl::CXXConversion: + case Decl::CXXDestructor: + case Decl::CXXConstructor: + valueKind = VK_PRValue; + break; } + + 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, @@ -3465,18 +3726,8 @@ static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, } ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, - PredefinedExpr::IdentKind IK) { - // Pick the current block, lambda, captured statement or function. - Decl *currentDecl = nullptr; - if (const BlockScopeInfo *BSI = getCurBlock()) - currentDecl = BSI->TheDecl; - else if (const LambdaScopeInfo *LSI = getCurLambda()) - currentDecl = LSI->CallOperator; - else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion()) - currentDecl = CSI->TheCapturedDecl; - else - currentDecl = getCurFunctionOrMethodDecl(); - + PredefinedIdentKind IK) { + Decl *currentDecl = getPredefinedExprDecl(CurContext); if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); currentDecl = Context.getTranslationUnitDecl(); @@ -3493,28 +3744,30 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, unsigned Length = Str.length(); llvm::APInt LengthI(32, Length + 1); - if (IK == PredefinedExpr::LFunction || IK == PredefinedExpr::LFuncSig) { + if (IK == PredefinedIdentKind::LFunction || + IK == PredefinedIdentKind::LFuncSig) { ResTy = Context.adjustStringLiteralBaseType(Context.WideCharTy.withConst()); SmallString<32> RawChars; ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), Str, RawChars); ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, - ArrayType::Normal, + ArraySizeModifier::Normal, /*IndexTypeQuals*/ 0); - SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide, + SL = StringLiteral::Create(Context, RawChars, StringLiteralKind::Wide, /*Pascal*/ false, ResTy, Loc); } else { ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, - ArrayType::Normal, + ArraySizeModifier::Normal, /*IndexTypeQuals*/ 0); - SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, + SL = StringLiteral::Create(Context, Str, StringLiteralKind::Ordinary, /*Pascal*/ false, ResTy, Loc); } } - return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); + return PredefinedExpr::Create(Context, Loc, ResTy, IK, LangOpts.MicrosoftExt, + SL); } ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, @@ -3540,20 +3793,7 @@ ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { - PredefinedExpr::IdentKind IK; - - switch (Kind) { - default: llvm_unreachable("Unknown simple primary expr!"); - case tok::kw___func__: IK = PredefinedExpr::Func; break; // [C99 6.4.2.2] - case tok::kw___FUNCTION__: IK = PredefinedExpr::Function; break; - case tok::kw___FUNCDNAME__: IK = PredefinedExpr::FuncDName; break; // [MS] - case tok::kw___FUNCSIG__: IK = PredefinedExpr::FuncSig; break; // [MS] - case tok::kw_L__FUNCTION__: IK = PredefinedExpr::LFunction; break; // [MS] - case tok::kw_L__FUNCSIG__: IK = PredefinedExpr::LFuncSig; break; // [MS] - case tok::kw___PRETTY_FUNCTION__: IK = PredefinedExpr::PrettyFunction; break; - } - - return BuildPredefinedExpr(Loc, IK); + return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind)); } ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { @@ -3571,6 +3811,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { QualType Ty; if (Literal.isWide()) Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++. + else if (Literal.isUTF8() && getLangOpts().C23) + Ty = Context.UnsignedCharTy; // u8'x' -> unsigned char in C23 else if (Literal.isUTF8() && getLangOpts().Char8) Ty = Context.Char8Ty; // u8'x' -> char8_t when it exists. else if (Literal.isUTF16()) @@ -3580,17 +3822,18 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { else if (!getLangOpts().CPlusPlus || Literal.isMultiChar()) Ty = Context.IntTy; // 'x' -> int in C, 'wxyz' -> int in C++. else - Ty = Context.CharTy; // 'x' -> char in C++ + Ty = Context.CharTy; // 'x' -> char in C++; + // u8'x' -> char in C11-C17 and in C++ without char8_t. - CharacterLiteral::CharacterKind Kind = CharacterLiteral::Ascii; + CharacterLiteralKind Kind = CharacterLiteralKind::Ascii; if (Literal.isWide()) - Kind = CharacterLiteral::Wide; + Kind = CharacterLiteralKind::Wide; else if (Literal.isUTF16()) - Kind = CharacterLiteral::UTF16; + Kind = CharacterLiteralKind::UTF16; else if (Literal.isUTF32()) - Kind = CharacterLiteral::UTF32; + Kind = CharacterLiteralKind::UTF32; else if (Literal.isUTF8()) - Kind = CharacterLiteral::UTF8; + Kind = CharacterLiteralKind::UTF8; Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty, Tok.getLocation()); @@ -3708,7 +3951,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Literal.hasUDSuffix()) { // We're building a user-defined literal. - IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); + const IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); SourceLocation UDSuffixLoc = getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset()); @@ -3771,10 +4014,11 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { unsigned Length = Literal.getUDSuffixOffset(); QualType StrTy = Context.getConstantArrayType( Context.adjustStringLiteralBaseType(Context.CharTy.withConst()), - llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0); - Expr *Lit = StringLiteral::Create( - Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, - /*Pascal*/false, StrTy, &TokLoc, 1); + llvm::APInt(32, Length + 1), nullptr, ArraySizeModifier::Normal, 0); + Expr *Lit = + StringLiteral::Create(Context, StringRef(TokSpelling.data(), Length), + StringLiteralKind::Ordinary, + /*Pascal*/ false, StrTy, &TokLoc, 1); return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc); } @@ -3793,7 +4037,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: @@ -3832,7 +4076,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { llvm::APInt Val(bit_width, 0, isSigned); bool Overflowed = Literal.GetFixedPointValue(Val, scale); - bool ValIsZero = Val.isNullValue() && !Overflowed; + bool ValIsZero = Val.isZero() && !Overflowed; auto MaxVal = Context.getFixedPointMax(Ty).getValue(); if (Literal.isFract && Val == MaxVal + 1 && !ValIsZero) @@ -3877,7 +4121,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { "cl_khr_fp64", getLangOpts())) { // Impose single-precision float type when cl_khr_fp64 is not enabled. Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64) - << (getLangOpts().OpenCLVersion >= 300); + << (getLangOpts().getOpenCLCompatibleVersion() >= 300); Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); } } @@ -3886,27 +4130,35 @@ 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. + // 'z/uz' literals are a C++23 feature. if (Literal.isSizeT) Diag(Tok.getLocation(), getLangOpts().CPlusPlus - ? getLangOpts().CPlusPlus2b + ? getLangOpts().CPlusPlus23 ? diag::warn_cxx20_compat_size_t_suffix - : diag::ext_cxx2b_size_t_suffix - : diag::err_cxx2b_size_t_suffix); - - // Get the value in the widest-possible width. - unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth(); - llvm::APInt ResultVal(MaxWidth, 0); + : diag::ext_cxx23_size_t_suffix + : diag::err_cxx23_size_t_suffix); + + // 'wb/uwb' literals are a C23 feature. We support _BitInt as a type in C++, + // but we do not currently support the suffix in C++ mode because it's not + // entirely clear whether WG21 will prefer this suffix to return a library + // type such as std::bit_int instead of returning a _BitInt. + if (Literal.isBitInt && !getLangOpts().CPlusPlus) + PP.Diag(Tok.getLocation(), getLangOpts().C23 + ? diag::warn_c23_compat_bitint_suffix + : diag::ext_c23_bitint_suffix); + + // Get the value in the widest-possible width. What is "widest" depends on + // whether the literal is a bit-precise integer or not. For a bit-precise + // integer type, try to scan the source to determine how many bits are + // needed to represent the value. This may seem a bit expensive, but trying + // to get the integer value from an overly-wide APInt is *extremely* + // expensive, so the naive approach of assuming + // llvm::IntegerType::MAX_INT_BITS is a big performance hit. + unsigned BitsNeeded = + Literal.isBitInt ? llvm::APInt::getSufficientBitsNeeded( + Literal.getLiteralDigits(), Literal.getRadix()) + : Context.getTargetInfo().getIntMaxTWidth(); + llvm::APInt ResultVal(BitsNeeded, 0); if (Literal.GetIntegerValue(ResultVal)) { // If this value didn't fit into uintmax_t, error and force to ull. @@ -3938,7 +4190,33 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } } - // Check C++2b size_t literals. + // Bit-precise integer literals are automagically-sized based on the + // width required by the literal. + if (Literal.isBitInt) { + // The signed version has one more bit for the sign value. There are no + // zero-width bit-precise integers, even if the literal value is 0. + Width = std::max(ResultVal.getActiveBits(), 1u) + + (Literal.isUnsigned ? 0u : 1u); + + // Diagnose if the width of the constant is larger than BITINT_MAXWIDTH, + // and reset the type to the largest supported width. + unsigned int MaxBitIntWidth = + Context.getTargetInfo().getMaxBitIntWidth(); + if (Width > MaxBitIntWidth) { + Diag(Tok.getLocation(), diag::err_integer_literal_too_large) + << Literal.isUnsigned; + Width = MaxBitIntWidth; + } + + // Reset the result value to the smaller APInt and select the correct + // type to be used. Note, we zext even for signed values because the + // literal itself is always an unsigned value (a preceeding - is a + // unary operator, not part of the literal). + ResultVal = ResultVal.zextOrTrunc(Width); + Ty = Context.getBitIntType(Literal.isUnsigned, Width); + } + + // Check C++23 size_t literals. if (Literal.isSizeT) { assert(!Literal.MicrosoftInteger && "size_t literals can't be Microsoft literals"); @@ -4018,6 +4296,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); } } @@ -4078,6 +4365,18 @@ static bool CheckVecStepTraitOperandType(Sema &S, QualType T, return false; } +static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange) { + // builtin_vectorelements supports both fixed-sized and scalable vectors. + if (!T->isVectorType() && !T->isSizelessVectorType()) + return S.Diag(Loc, diag::err_builtin_non_vector_type) + << "" + << "__builtin_vectorelements" << T << ArgRange; + + return false; +} + static bool CheckExtensionTraitOperandType(Sema &S, QualType T, SourceLocation Loc, SourceRange ArgRange, @@ -4127,13 +4426,13 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, /// Check whether E is a pointer from a decayed array type (the decayed /// pointer type is equal to T) and emit a warning if it is. static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T, - Expr *E) { + const Expr *E) { // Don't warn if the operation changed the type. if (T != E->getType()) return; // Now look for array decays. - ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E); + const auto *ICE = dyn_cast<ImplicitCastExpr>(E); if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay) return; @@ -4155,8 +4454,9 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, assert(!ExprTy->isReferenceType()); bool IsUnevaluatedOperand = - (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || - ExprKind == UETT_PreferredAlignOf || ExprKind == UETT_VecStep); + (ExprKind == UETT_SizeOf || ExprKind == UETT_DataSizeOf || + ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf || + ExprKind == UETT_VecStep); if (IsUnevaluatedOperand) { ExprResult Result = CheckUnevaluatedOperand(E); if (Result.isInvalid()) @@ -4171,6 +4471,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // FIXME: Should we consider instantiation-dependent operands to 'alignof'? if (IsUnevaluatedOperand && !inTemplateInstantiation() && !E->isInstantiationDependent() && + !E->getType()->isVariableArrayType() && E->HasSideEffects(Context, false)) Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); @@ -4178,11 +4479,24 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange()); + if (ExprKind == UETT_VectorElements) + return CheckVectorElementsTraitOperandType(*this, ExprTy, E->getExprLoc(), + E->getSourceRange()); + // Explicitly list some types as extensions. if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) return false; + // WebAssembly tables are always illegal operands to unary expressions and + // type traits. + if (Context.getTargetInfo().getTriple().isWasm() && + E->getType()->isWebAssemblyTableType()) { + Diag(E->getExprLoc(), diag::err_wasm_table_invalid_uett_operand) + << getTraitSpelling(ExprKind); + return true; + } + // 'alignof' applied to an expression only requires the base element type of // the expression to be complete. 'sizeof' requires the expression's type to // be complete (and will attempt to complete it if it's an array of unknown @@ -4215,8 +4529,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return true; if (ExprKind == UETT_SizeOf) { - if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { - if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { + if (const auto *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { + if (const auto *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { QualType OType = PVD->getOriginalType(); QualType Type = PVD->getType(); if (Type->isPointerType() && OType->isArrayType()) { @@ -4230,7 +4544,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // Warn on "sizeof(array op x)" and "sizeof(x op array)", where the array // decays into a pointer and returns an unintended result. This is most // likely a typo for "sizeof(array) op x". - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) { + if (const auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) { warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), BO->getLHS()); warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), @@ -4241,70 +4555,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return false; } -/// Check the constraints on operands to unary expression and type -/// traits. -/// -/// This will complete any types necessary, and validate the various constraints -/// on those operands. -/// -/// The UsualUnaryConversions() function is *not* called by this routine. -/// C99 6.3.2.1p[2-4] all state: -/// Except when it is the operand of the sizeof operator ... -/// -/// C++ [expr.sizeof]p4 -/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer -/// standard conversions are not applied to the operand of sizeof. -/// -/// This policy is followed for all of the unary trait expressions. -bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, - SourceLocation OpLoc, - SourceRange ExprRange, - UnaryExprOrTypeTrait ExprKind) { - if (ExprType->isDependentType()) - return false; - - // C++ [expr.sizeof]p2: - // When applied to a reference or a reference type, the result - // is the size of the referenced type. - // C++11 [expr.alignof]p3: - // When alignof is applied to a reference type, the result - // shall be the alignment of the referenced type. - if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>()) - ExprType = Ref->getPointeeType(); - - // C11 6.5.3.4/3, C++11 [expr.alignof]p3: - // When alignof or _Alignof is applied to an array type, the result - // is the alignment of the element type. - if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf || - ExprKind == UETT_OpenMPRequiredSimdAlign) - ExprType = Context.getBaseElementType(ExprType); - - if (ExprKind == UETT_VecStep) - return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); - - // Explicitly list some types as extensions. - if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, - ExprKind)) - return false; - - if (RequireCompleteSizedType( - OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, - getTraitSpelling(ExprKind), ExprRange)) - return true; - - if (ExprType->isFunctionType()) { - Diag(OpLoc, diag::err_sizeof_alignof_function_type) - << getTraitSpelling(ExprKind) << ExprRange; - return true; - } - - if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, - ExprKind)) - return true; - - return false; -} - static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) @@ -4396,15 +4646,17 @@ 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: case Type::ObjCObjectPointer: case Type::ObjCTypeParam: case Type::Pipe: - case Type::ExtInt: + 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; @@ -4451,6 +4703,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::TypeOf: case Type::UnaryTransform: case Type::Attributed: + case Type::BTFTagAttributed: case Type::SubstTemplateTypeParm: case Type::MacroQualified: // Keep walking after single level desugaring. @@ -4462,6 +4715,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Decltype: T = cast<DecltypeType>(Ty)->desugar(); break; + case Type::Using: + T = cast<UsingType>(Ty)->desugar(); + break; case Type::Auto: case Type::DeducedTemplateSpecialization: T = cast<DeducedType>(Ty)->getDeducedType(); @@ -4476,23 +4732,82 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, } while (!T.isNull() && T->isVariablyModifiedType()); } -/// Build a sizeof or alignof expression given a type operand. -ExprResult -Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, - SourceRange R) { - if (!TInfo) - return ExprError(); +/// Check the constraints on operands to unary expression and type +/// traits. +/// +/// This will complete any types necessary, and validate the various constraints +/// on those operands. +/// +/// The UsualUnaryConversions() function is *not* called by this routine. +/// C99 6.3.2.1p[2-4] all state: +/// Except when it is the operand of the sizeof operator ... +/// +/// C++ [expr.sizeof]p4 +/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer +/// standard conversions are not applied to the operand of sizeof. +/// +/// This policy is followed for all of the unary trait expressions. +bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, + SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind, + StringRef KWName) { + if (ExprType->isDependentType()) + return false; - QualType T = TInfo->getType(); + // C++ [expr.sizeof]p2: + // When applied to a reference or a reference type, the result + // is the size of the referenced type. + // C++11 [expr.alignof]p3: + // When alignof is applied to a reference type, the result + // shall be the alignment of the referenced type. + if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>()) + ExprType = Ref->getPointeeType(); - if (!T->isDependentType() && - CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) - return ExprError(); + // C11 6.5.3.4/3, C++11 [expr.alignof]p3: + // When alignof or _Alignof is applied to an array type, the result + // is the alignment of the element type. + if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf || + ExprKind == UETT_OpenMPRequiredSimdAlign) + ExprType = Context.getBaseElementType(ExprType); + + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); + + if (ExprKind == UETT_VectorElements) + return CheckVectorElementsTraitOperandType(*this, ExprType, OpLoc, + ExprRange); + + // Explicitly list some types as extensions. + if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, + ExprKind)) + return false; + + if (RequireCompleteSizedType( + OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, + KWName, ExprRange)) + return true; + + if (ExprType->isFunctionType()) { + Diag(OpLoc, diag::err_sizeof_alignof_function_type) << KWName << ExprRange; + return true; + } + + // WebAssembly tables are always illegal operands to unary expressions and + // type traits. + if (Context.getTargetInfo().getTriple().isWasm() && + ExprType->isWebAssemblyTableType()) { + Diag(OpLoc, diag::err_wasm_table_invalid_uett_operand) + << getTraitSpelling(ExprKind); + return true; + } + + if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, + ExprKind)) + return true; - if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) { - if (auto *TT = T->getAs<TypedefType>()) { + if (ExprType->isVariablyModifiedType() && FunctionScopes.size() > 1) { + if (auto *TT = ExprType->getAs<TypedefType>()) { for (auto I = FunctionScopes.rbegin(), E = std::prev(FunctionScopes.rend()); I != E; ++I) { @@ -4509,12 +4824,36 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, if (DC) { if (DC->containsDecl(TT->getDecl())) break; - captureVariablyModifiedType(Context, T, CSI); + captureVariablyModifiedType(Context, ExprType, CSI); } } } } + return false; +} + +/// Build a sizeof or alignof expression given a type operand. +ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { + if (!TInfo) + return ExprError(); + + QualType T = TInfo->getType(); + + if (!T->isDependentType() && + CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind, + getTraitSpelling(ExprKind))) + return ExprError(); + + // Adds overload of TransformToPotentiallyEvaluated for TypeSourceInfo to + // properly deal with VLAs in nested calls of sizeof and typeof. + if (isUnevaluatedContext() && ExprKind == UETT_SizeOf && + TInfo->getType()->isVariablyModifiedType()) + TInfo = TransformToPotentiallyEvaluated(TInfo); + // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. return new (Context) UnaryExprOrTypeTraitExpr( ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); @@ -4545,6 +4884,8 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, } else if (E->refersToBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 0; isInvalid = true; + } else if (ExprKind == UETT_VectorElements) { + isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_VectorElements); } else { isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); } @@ -4584,6 +4925,29 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, return Result; } +bool Sema::CheckAlignasTypeArgument(StringRef KWName, TypeSourceInfo *TInfo, + SourceLocation OpLoc, SourceRange R) { + if (!TInfo) + return true; + return CheckUnaryExprOrTypeTraitOperand(TInfo->getType(), OpLoc, R, + UETT_AlignOf, KWName); +} + +/// ActOnAlignasTypeArgument - Handle @c alignas(type-id) and @c +/// _Alignas(type-name) . +/// [dcl.align] An alignment-specifier of the form +/// alignas(type-id) has the same effect as alignas(alignof(type-id)). +/// +/// [N1570 6.7.5] _Alignas(type-name) is equivalent to +/// _Alignas(_Alignof(type-name)). +bool Sema::ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty, + SourceLocation OpLoc, SourceRange R) { + TypeSourceInfo *TInfo; + (void)GetTypeFromParser(ParsedType::getFromOpaquePtr(Ty.getAsOpaquePtr()), + &TInfo); + return CheckAlignasTypeArgument(KWName, TInfo, OpLoc, R); +} + static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, bool IsReal) { if (V.get()->isTypeDependent()) @@ -4662,19 +5026,54 @@ static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) { return isa<MSPropertySubscriptExpr>(BaseNoParens); } -ExprResult -Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, - Expr *idx, SourceLocation rbLoc) { +// Returns the type used for LHS[RHS], given one of LHS, RHS is type-dependent. +// Typically this is DependentTy, but can sometimes be more precise. +// +// There are cases when we could determine a non-dependent type: +// - LHS and RHS may have non-dependent types despite being type-dependent +// (e.g. unbounded array static members of the current instantiation) +// - one may be a dependent-sized array with known element type +// - one may be a dependent-typed valid index (enum in current instantiation) +// +// We *always* return a dependent type, in such cases it is DependentTy. +// This avoids creating type-dependent expressions with non-dependent types. +// FIXME: is this important to avoid? See https://reviews.llvm.org/D107275 +static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS, + const ASTContext &Ctx) { + assert(LHS->isTypeDependent() || RHS->isTypeDependent()); + QualType LTy = LHS->getType(), RTy = RHS->getType(); + QualType Result = Ctx.DependentTy; + if (RTy->isIntegralOrUnscopedEnumerationType()) { + if (const PointerType *PT = LTy->getAs<PointerType>()) + Result = PT->getPointeeType(); + else if (const ArrayType *AT = LTy->getAsArrayTypeUnsafe()) + Result = AT->getElementType(); + } else if (LTy->isIntegralOrUnscopedEnumerationType()) { + if (const PointerType *PT = RTy->getAs<PointerType>()) + Result = PT->getPointeeType(); + else if (const ArrayType *AT = RTy->getAsArrayTypeUnsafe()) + Result = AT->getElementType(); + } + // Ensure we return a dependent type. + return Result->isDependentType() ? Result : Ctx.DependentTy; +} + +ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, + SourceLocation lbLoc, + MultiExprArg ArgExprs, + SourceLocation rbLoc) { + if (base && !base->getType().isNull() && - base->getType()->isSpecificPlaceholderType(BuiltinType::OMPArraySection)) - return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(), + base->hasPlaceholderType(BuiltinType::OMPArraySection)) + return ActOnOMPArraySectionExpr(base, lbLoc, ArgExprs.front(), SourceLocation(), SourceLocation(), /*Length*/ nullptr, /*Stride=*/nullptr, rbLoc); // Since this might be a postfix expression, get rid of ParenListExprs. if (isa<ParenListExpr>(base)) { ExprResult result = MaybeConvertParenListExprToParenExpr(S, base); - if (result.isInvalid()) return ExprError(); + if (result.isInvalid()) + return ExprError(); base = result.get(); } @@ -4692,8 +5091,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, }; // The matrix subscript operator ([][])is considered a single operator. // Separating the index expressions by parenthesis is not allowed. - if (base->getType()->isSpecificPlaceholderType( - BuiltinType::IncompleteMatrixIdx) && + if (base && !base->getType().isNull() && + base->hasPlaceholderType(BuiltinType::IncompleteMatrixIdx) && !isa<MatrixSubscriptExpr>(base)) { Diag(base->getExprLoc(), diag::err_matrix_separate_incomplete_index) << SourceRange(base->getBeginLoc(), rbLoc); @@ -4703,13 +5102,20 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // MatrixSubscriptExpr. auto *matSubscriptE = dyn_cast<MatrixSubscriptExpr>(base); if (matSubscriptE) { - if (CheckAndReportCommaError(idx)) + assert(ArgExprs.size() == 1); + if (CheckAndReportCommaError(ArgExprs.front())) return ExprError(); assert(matSubscriptE->isIncomplete() && "base has to be an incomplete matrix subscript"); - return CreateBuiltinMatrixSubscriptExpr( - matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc); + return CreateBuiltinMatrixSubscriptExpr(matSubscriptE->getBase(), + matSubscriptE->getRowIdx(), + ArgExprs.front(), rbLoc); + } + if (base->getType()->isWebAssemblyTableType()) { + Diag(base->getExprLoc(), diag::err_wasm_table_art) + << SourceRange(base->getBeginLoc(), rbLoc) << 3; + return ExprError(); } // Handle any non-overload placeholder types in the base and index @@ -4730,32 +5136,44 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // If the base is a matrix type, try to create a new MatrixSubscriptExpr. if (base->getType()->isMatrixType()) { - if (CheckAndReportCommaError(idx)) + assert(ArgExprs.size() == 1); + if (CheckAndReportCommaError(ArgExprs.front())) return ExprError(); - return CreateBuiltinMatrixSubscriptExpr(base, idx, nullptr, rbLoc); + return CreateBuiltinMatrixSubscriptExpr(base, ArgExprs.front(), nullptr, + rbLoc); } - // A comma-expression as the index is deprecated in C++2a onwards. - if (getLangOpts().CPlusPlus20 && - ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) || - (isa<CXXOperatorCallExpr>(idx) && - cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) { - Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript) - << SourceRange(base->getBeginLoc(), rbLoc); + if (ArgExprs.size() == 1 && getLangOpts().CPlusPlus20) { + Expr *idx = ArgExprs[0]; + if ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) || + (isa<CXXOperatorCallExpr>(idx) && + cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma)) { + Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript) + << SourceRange(base->getBeginLoc(), rbLoc); + } } - if (idx->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(idx); - if (result.isInvalid()) return ExprError(); - idx = result.get(); + if (ArgExprs.size() == 1 && + ArgExprs[0]->getType()->isNonOverloadPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(ArgExprs[0]); + if (result.isInvalid()) + return ExprError(); + ArgExprs[0] = result.get(); + } else { + if (CheckArgsForPlaceholders(ArgExprs)) + return ExprError(); } // Build an unanalyzed expression if either operand is type-dependent. - if (getLangOpts().CPlusPlus && - (base->isTypeDependent() || idx->isTypeDependent())) { - return new (Context) ArraySubscriptExpr(base, idx, Context.DependentTy, - VK_LValue, OK_Ordinary, rbLoc); + if (getLangOpts().CPlusPlus && ArgExprs.size() == 1 && + (base->isTypeDependent() || + Expr::hasAnyTypeDependentArguments(ArgExprs)) && + !isa<PackExpansionExpr>(ArgExprs[0])) { + return new (Context) ArraySubscriptExpr( + base, ArgExprs.front(), + getDependentArraySubscriptType(base, ArgExprs.front(), getASTContext()), + VK_LValue, OK_Ordinary, rbLoc); } // MSDN, property (C++) @@ -4767,10 +5185,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), // and p->x[a][b] = i will be turned into p->PutX(a, b, i); if (IsMSPropertySubscript) { + assert(ArgExprs.size() == 1); // Build MS property subscript expression if base is MS property reference // or MS property subscript. - return new (Context) MSPropertySubscriptExpr( - base, idx, Context.PseudoObjectTy, VK_LValue, OK_Ordinary, rbLoc); + return new (Context) + MSPropertySubscriptExpr(base, ArgExprs.front(), Context.PseudoObjectTy, + VK_LValue, OK_Ordinary, rbLoc); } // Use C++ overloaded-operator rules if either operand has record @@ -4781,14 +5201,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // // ObjC pointers have their own subscripting logic that is not tied // to overload resolution and so should not take this path. - if (getLangOpts().CPlusPlus && - (base->getType()->isRecordType() || - (!base->getType()->isObjCObjectPointerType() && - idx->getType()->isRecordType()))) { - return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx); + if (getLangOpts().CPlusPlus && !base->getType()->isObjCObjectPointerType() && + ((base->getType()->isRecordType() || + (ArgExprs.size() != 1 || isa<PackExpansionExpr>(ArgExprs[0]) || + ArgExprs[0]->getType()->isRecordType())))) { + return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, ArgExprs); } - ExprResult Res = CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc); + ExprResult Res = + CreateBuiltinArraySubscriptExpr(base, lbLoc, ArgExprs.front(), rbLoc); if (!Res.isInvalid() && isa<ArraySubscriptExpr>(Res.get())) CheckSubscriptAccessOfNoDeref(cast<ArraySubscriptExpr>(Res.get())); @@ -4844,7 +5265,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) @@ -4924,9 +5345,8 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, SourceLocation ColonLocSecond, Expr *Length, Expr *Stride, SourceLocation RBLoc) { - if (Base->getType()->isPlaceholderType() && - !Base->getType()->isSpecificPlaceholderType( - BuiltinType::OMPArraySection)) { + if (Base->hasPlaceholderType() && + !Base->hasPlaceholderType(BuiltinType::OMPArraySection)) { ExprResult Result = CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); @@ -5094,8 +5514,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, } } - if (!Base->getType()->isSpecificPlaceholderType( - BuiltinType::OMPArraySection)) { + if (!Base->hasPlaceholderType(BuiltinType::OMPArraySection)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(Base); if (Result.isInvalid()) return ExprError(); @@ -5110,7 +5529,7 @@ ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, SourceLocation RParenLoc, ArrayRef<Expr *> Dims, ArrayRef<SourceRange> Brackets) { - if (Base->getType()->isPlaceholderType()) { + if (Base->hasPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); @@ -5135,7 +5554,7 @@ ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, SmallVector<Expr *, 4> NewDims; bool ErrorFound = false; for (Expr *Dim : Dims) { - if (Dim->getType()->isPlaceholderType()) { + if (Dim->hasPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(Dim); if (Result.isInvalid()) { ErrorFound = true; @@ -5250,6 +5669,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 = @@ -5269,11 +5692,12 @@ 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. - if (Result && Result->isNullValue()) { + if (Result && Result->isZero()) { Diag(Step->getExprLoc(), diag::err_omp_iterator_step_constant_zero) << Step << Step->getSourceRange(); IsCorrect = false; @@ -5509,7 +5933,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, if (LHSTy->isDependentType() || RHSTy->isDependentType()) { BaseExpr = LHSExp; IndexExpr = RHSExp; - ResultType = Context.DependentTy; + ResultType = + getDependentArraySubscriptType(LHSExp, RHSExp, getASTContext()); } else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) { BaseExpr = LHSExp; IndexExpr = RHSExp; @@ -5563,6 +5988,33 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) ResultType = Context.getQualifiedType(ResultType, Combined); + } else if (LHSTy->isBuiltinType() && + LHSTy->getAs<BuiltinType>()->isSveVLSBuiltinType()) { + const BuiltinType *BTy = LHSTy->getAs<BuiltinType>(); + if (BTy->isSVEBool()) + return ExprError(Diag(LLoc, diag::err_subscript_svbool_t) + << LHSExp->getSourceRange() << RHSExp->getSourceRange()); + + BaseExpr = LHSExp; + IndexExpr = RHSExp; + if (getLangOpts().CPlusPlus11 && LHSExp->isPRValue()) { + ExprResult Materialized = TemporaryMaterializationConversion(LHSExp); + if (Materialized.isInvalid()) + return ExprError(); + LHSExp = Materialized.get(); + } + VK = LHSExp->getValueKind(); + if (VK != VK_PRValue) + OK = OK_VectorComponent; + + ResultType = BTy->getSveEltType(Context); + + QualType BaseType = BaseExpr->getType(); + Qualifiers BaseQuals = BaseType.getQualifiers(); + Qualifiers MemberQuals = ResultType.getQualifiers(); + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + ResultType = Context.getQualifiedType(ResultType, Combined); } else if (LHSTy->isArrayType()) { // If we see an array that wasn't promoted by // DefaultFunctionArrayLvalueConversion, it must be an array that @@ -5599,9 +6051,14 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, << IndexExpr->getSourceRange()); if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || - IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) - && !IndexExpr->isTypeDependent()) - Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange(); + IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) && + !IndexExpr->isTypeDependent()) { + std::optional<llvm::APSInt> IntegerContantExpr = + IndexExpr->getIntegerConstantExpr(getASTContext()); + if (!IntegerContantExpr.has_value() || + IntegerContantExpr.value().isNegative()) + Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange(); + } // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, // C++ [expr.sub]p1: The type "T" shall be a completely-defined object @@ -5623,6 +6080,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, if (!ResultType.hasQualifiers()) VK = VK_PRValue; } else if (!ResultType->isDependentType() && + !ResultType.isWebAssemblyReferenceType() && RequireCompleteSizedType( LLoc, ResultType, diag::err_subscript_incomplete_or_sizeless_type, BaseExpr)) @@ -5663,8 +6121,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)) { @@ -5681,11 +6141,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 @@ -5694,41 +6157,293 @@ 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". + // C++ [expr.const]p15.1: + // An expression or conversion is in an immediate function context if it is + // potentially evaluated and [...] its innermost enclosing non-block scope + // is a function parameter scope of an immediate function. EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); - MarkDeclarationsReferencedInExpr(Param->getDefaultArg(), - /*SkipLocalVariables=*/true); + *this, + FD->isImmediateFunction() + ? ExpressionEvaluationContext::ImmediateFunctionContext + : ExpressionEvaluationContext::PotentiallyEvaluated, + Param); + ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = + SkipImmediateInvocations; + runWithSufficientStackSpace(CallLoc, [&] { + MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables=*/true); + }); return false; } +struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> { + const ASTContext &Context; + ImmediateCallVisitor(const ASTContext &Ctx) : Context(Ctx) {} + + bool HasImmediateCalls = false; + bool shouldVisitImplicitCode() const { return true; } + + bool VisitCallExpr(CallExpr *E) { + if (const FunctionDecl *FD = E->getDirectCallee()) + HasImmediateCalls |= FD->isImmediateFunction(); + 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. + // C++ [expr.const]p15.1: + // An expression or conversion is in an immediate function context if it + // is potentially evaluated and [...] its innermost enclosing non-block + // scope is a function parameter scope of an immediate function. + EnterExpressionEvaluationContext EvalContext( + *this, + FD->isImmediateFunction() + ? ExpressionEvaluationContext::ImmediateFunctionContext + : 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(getASTContext()); + if (!NestedDefaultChecking) + V.TraverseDecl(Param); + if (V.HasImmediateCalls) { + ExprEvalContexts.back().DelayedDefaultInitializationContext = { + CallLoc, Param, CurContext}; + EnsureImmediateInvocationInDefaultArgs Immediate(*this); + ExprResult Res; + runWithSufficientStackSpace(CallLoc, [&] { + 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(); + + CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers()); + + 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(getASTContext()); + if (!NestedDefaultChecking) + V.TraverseDecl(Field); + if (V.HasImmediateCalls) { + ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field, + CurContext}; + ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = + NestedDefaultChecking; + + EnsureImmediateInvocationInDefaultArgs Immediate(*this); + ExprResult Res; + runWithSufficientStackSpace(Loc, [&] { + 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) + runWithSufficientStackSpace(Loc, [&] { + 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 Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn) { if (Proto && Proto->isVariadic()) { - if (dyn_cast_or_null<CXXConstructorDecl>(FDecl)) + if (isa_and_nonnull<CXXConstructorDecl>(FDecl)) return VariadicConstructor; else if (Fn && Fn->getType()->isBlockPointerType()) return VariadicBlock; @@ -5828,6 +6543,9 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by // assignment, to the types of the corresponding parameter, ... + bool HasExplicitObjectParameter = + FDecl && FDecl->hasCXXExplicitFunctionObjectParameter(); + unsigned ExplicitObjectParameterOffset = HasExplicitObjectParameter ? 1 : 0; unsigned NumParams = Proto->getNumParams(); bool Invalid = false; unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumParams; @@ -5846,25 +6564,34 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args_suggest : diag::err_typecheck_call_too_few_args_at_least_suggest; - diagnoseTypo(TC, PDiag(diag_id) << FnKind << MinArgs - << static_cast<unsigned>(Args.size()) - << TC.getCorrectionRange()); - } else if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName()) + diagnoseTypo( + TC, PDiag(diag_id) + << FnKind << MinArgs - ExplicitObjectParameterOffset + << static_cast<unsigned>(Args.size()) - + ExplicitObjectParameterOffset + << HasExplicitObjectParameter << TC.getCorrectionRange()); + } else if (MinArgs - ExplicitObjectParameterOffset == 1 && FDecl && + FDecl->getParamDecl(ExplicitObjectParameterOffset) + ->getDeclName()) Diag(RParenLoc, MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args_one : diag::err_typecheck_call_too_few_args_at_least_one) - << FnKind << FDecl->getParamDecl(0) << Fn->getSourceRange(); + << FnKind << FDecl->getParamDecl(ExplicitObjectParameterOffset) + << HasExplicitObjectParameter << Fn->getSourceRange(); else Diag(RParenLoc, MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args : diag::err_typecheck_call_too_few_args_at_least) - << FnKind << MinArgs << static_cast<unsigned>(Args.size()) - << Fn->getSourceRange(); + << FnKind << MinArgs - ExplicitObjectParameterOffset + << static_cast<unsigned>(Args.size()) - + ExplicitObjectParameterOffset + << HasExplicitObjectParameter << Fn->getSourceRange(); // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) - Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; + Diag(FDecl->getLocation(), diag::note_callee_decl) + << FDecl << FDecl->getParametersSourceRange(); return true; } @@ -5884,17 +6611,23 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_many_args_suggest : diag::err_typecheck_call_too_many_args_at_most_suggest; - diagnoseTypo(TC, PDiag(diag_id) << FnKind << NumParams - << static_cast<unsigned>(Args.size()) - << TC.getCorrectionRange()); - } else if (NumParams == 1 && FDecl && - FDecl->getParamDecl(0)->getDeclName()) + diagnoseTypo( + TC, PDiag(diag_id) + << FnKind << NumParams - ExplicitObjectParameterOffset + << static_cast<unsigned>(Args.size()) - + ExplicitObjectParameterOffset + << HasExplicitObjectParameter << TC.getCorrectionRange()); + } else if (NumParams - ExplicitObjectParameterOffset == 1 && FDecl && + FDecl->getParamDecl(ExplicitObjectParameterOffset) + ->getDeclName()) Diag(Args[NumParams]->getBeginLoc(), MinArgs == NumParams ? diag::err_typecheck_call_too_many_args_one : diag::err_typecheck_call_too_many_args_at_most_one) - << FnKind << FDecl->getParamDecl(0) - << static_cast<unsigned>(Args.size()) << Fn->getSourceRange() + << FnKind << FDecl->getParamDecl(ExplicitObjectParameterOffset) + << static_cast<unsigned>(Args.size()) - + ExplicitObjectParameterOffset + << HasExplicitObjectParameter << Fn->getSourceRange() << SourceRange(Args[NumParams]->getBeginLoc(), Args.back()->getEndLoc()); else @@ -5902,14 +6635,17 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, MinArgs == NumParams ? diag::err_typecheck_call_too_many_args : diag::err_typecheck_call_too_many_args_at_most) - << FnKind << NumParams << static_cast<unsigned>(Args.size()) - << Fn->getSourceRange() + << FnKind << NumParams - ExplicitObjectParameterOffset + << static_cast<unsigned>(Args.size()) - + ExplicitObjectParameterOffset + << HasExplicitObjectParameter << Fn->getSourceRange() << SourceRange(Args[NumParams]->getBeginLoc(), Args.back()->getEndLoc()); // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) - Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; + Diag(FDecl->getLocation(), diag::note_callee_decl) + << FDecl << FDecl->getParametersSourceRange(); // This deletes the extra arguments. Call->shrinkNumArgs(NumParams); @@ -6063,7 +6799,7 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, QualType OrigTy = Param->getOriginalType(); const ArrayType *AT = Context.getAsArrayType(OrigTy); - if (!AT || AT->getSizeModifier() != ArrayType::Static) + if (!AT || AT->getSizeModifier() != ArraySizeModifier::Static) return; if (ArgExpr->isNullPointerConstant(Context, @@ -6094,9 +6830,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() @@ -6134,6 +6871,8 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" +#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/WebAssemblyReferenceTypes.def" #define PLACEHOLDER_TYPE(ID, SINGLETON_ID) #define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: #include "clang/AST/BuiltinTypes.def" @@ -6171,15 +6910,13 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { llvm_unreachable("bad builtin type kind"); } -/// Check an argument list for placeholders that we won't try to -/// handle later. -static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { +bool Sema::CheckArgsForPlaceholders(MultiExprArg args) { // Apply this processing to all the arguments at once instead of // dying at the first failure. bool hasInvalid = false; for (size_t i = 0, e = args.size(); i != e; i++) { if (isPlaceholderToRemoveAsArg(args[i]->getType())) { - ExprResult result = S.CheckPlaceholderExpr(args[i]); + ExprResult result = CheckPlaceholderExpr(args[i]); if (result.isInvalid()) hasInvalid = true; else args[i] = result.get(); } @@ -6222,10 +6959,10 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, return nullptr; Expr *Arg = ArgRes.get(); QualType ArgType = Arg->getType(); - if (!ParamType->isPointerType() || - ParamType.hasAddressSpace() || + if (!ParamType->isPointerType() || ParamType.hasAddressSpace() || !ArgType->isPointerType() || - !ArgType->getPointeeType().hasAddressSpace()) { + !ArgType->getPointeeType().hasAddressSpace() || + isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) { OverloadParams.push_back(ParamType); continue; } @@ -6249,14 +6986,12 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, QualType OverloadTy = Context.getFunctionType(FT->getReturnType(), OverloadParams, EPI); DeclContext *Parent = FDecl->getParent(); - FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent, - FDecl->getLocation(), - FDecl->getLocation(), - FDecl->getIdentifier(), - OverloadTy, - /*TInfo=*/nullptr, - SC_Extern, false, - /*hasPrototype=*/true); + FunctionDecl *OverloadDecl = FunctionDecl::Create( + Context, Parent, FDecl->getLocation(), FDecl->getLocation(), + FDecl->getIdentifier(), OverloadTy, + /*TInfo=*/nullptr, SC_Extern, Sema->getCurFPFeatures().isFPConstrained(), + false, + /*hasPrototype=*/true); SmallVector<ParmVarDecl*, 16> Params; FT = cast<FunctionProtoType>(OverloadTy); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { @@ -6381,6 +7116,38 @@ tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( } } +// Once a call is fully resolved, warn for unqualified calls to specific +// C++ standard functions, like move and forward. +static void DiagnosedUnqualifiedCallsToStdFunctions(Sema &S, + const CallExpr *Call) { + // We are only checking unary move and forward so exit early here. + if (Call->getNumArgs() != 1) + return; + + const Expr *E = Call->getCallee()->IgnoreParenImpCasts(); + if (!E || isa<UnresolvedLookupExpr>(E)) + return; + const DeclRefExpr *DRE = dyn_cast_if_present<DeclRefExpr>(E); + if (!DRE || !DRE->getLocation().isValid()) + return; + + if (DRE->getQualifier()) + return; + + const FunctionDecl *FD = Call->getDirectCallee(); + if (!FD) + return; + + // Only warn for some functions deemed more frequent or problematic. + unsigned BuiltinID = FD->getBuiltinID(); + if (BuiltinID != Builtin::BImove && BuiltinID != Builtin::BIforward) + return; + + S.Diag(DRE->getLocation(), diag::warn_unqualified_call_to_std_cast_function) + << FD->getQualifiedNameAsString() + << FixItHint::CreateInsertion(DRE->getLocation(), "std::"); +} + ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig) { @@ -6392,20 +7159,22 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, // Diagnose uses of the C++20 "ADL-only template-id call" feature in earlier // language modes. - if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn)) { - if (ULE->hasExplicitTemplateArgs() && - ULE->decls_begin() == ULE->decls_end()) { - Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus20 - ? diag::warn_cxx17_compat_adl_only_template_id - : diag::ext_adl_only_template_id) - << ULE->getName(); - } + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn); + ULE && ULE->hasExplicitTemplateArgs() && + ULE->decls_begin() == ULE->decls_end()) { + Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus20 + ? diag::warn_cxx17_compat_adl_only_template_id + : diag::ext_adl_only_template_id) + << ULE->getName(); } if (LangOpts.OpenMP) Call = ActOnOpenMPCall(Call, Scope, LParenLoc, ArgExprs, RParenLoc, ExecConfig); - + if (LangOpts.CPlusPlus) { + if (const auto *CE = dyn_cast<CallExpr>(Call.get())) + DiagnosedUnqualifiedCallsToStdFunctions(*this, CE); + } return Call; } @@ -6421,7 +7190,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Result.isInvalid()) return ExprError(); Fn = Result.get(); - if (checkArgsForPlaceholders(*this, ArgExprs)) + if (CheckArgsForPlaceholders(ArgExprs)) return ExprError(); if (getLangOpts().CPlusPlus) { @@ -6476,7 +7245,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.BoundMemberTy) { return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, - RParenLoc, AllowRecovery); + RParenLoc, ExecConfig, IsExecConfig, + AllowRecovery); } } @@ -6495,7 +7265,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, Scope, Fn, ULE, LParenLoc, ArgExprs, RParenLoc, ExecConfig, /*AllowTypoCorrection=*/true, find.IsAddressOfOperand); return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, - RParenLoc, AllowRecovery); + RParenLoc, ExecConfig, IsExecConfig, + AllowRecovery); } } @@ -6534,8 +7305,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( @@ -6543,6 +7314,57 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, return ExprError(); checkDirectCallValidity(*this, Fn, FD, ArgExprs); + + // If this expression is a call to a builtin function in HIP device + // compilation, allow a pointer-type argument to default address space to be + // passed as a pointer-type parameter to a non-default address space. + // If Arg is declared in the default address space and Param is declared + // in a non-default address space, perform an implicit address space cast to + // the parameter type. + if (getLangOpts().HIP && getLangOpts().CUDAIsDevice && FD && + FD->getBuiltinID()) { + for (unsigned Idx = 0; Idx < FD->param_size(); ++Idx) { + ParmVarDecl *Param = FD->getParamDecl(Idx); + if (!ArgExprs[Idx] || !Param || !Param->getType()->isPointerType() || + !ArgExprs[Idx]->getType()->isPointerType()) + continue; + + auto ParamAS = Param->getType()->getPointeeType().getAddressSpace(); + auto ArgTy = ArgExprs[Idx]->getType(); + auto ArgPtTy = ArgTy->getPointeeType(); + auto ArgAS = ArgPtTy.getAddressSpace(); + + // Add address space cast if target address spaces are different + bool NeedImplicitASC = + ParamAS != LangAS::Default && // Pointer params in generic AS don't need special handling. + ( ArgAS == LangAS::Default || // We do allow implicit conversion from generic AS + // or from specific AS which has target AS matching that of Param. + getASTContext().getTargetAddressSpace(ArgAS) == getASTContext().getTargetAddressSpace(ParamAS)); + if (!NeedImplicitASC) + continue; + + // First, ensure that the Arg is an RValue. + if (ArgExprs[Idx]->isGLValue()) { + ArgExprs[Idx] = ImplicitCastExpr::Create( + Context, ArgExprs[Idx]->getType(), CK_NoOp, ArgExprs[Idx], + nullptr, VK_PRValue, FPOptionsOverride()); + } + + // Construct a new arg type with address space of Param + Qualifiers ArgPtQuals = ArgPtTy.getQualifiers(); + ArgPtQuals.setAddressSpace(ParamAS); + auto NewArgPtTy = + Context.getQualifiedType(ArgPtTy.getUnqualifiedType(), ArgPtQuals); + auto NewArgTy = + Context.getQualifiedType(Context.getPointerType(NewArgPtTy), + ArgTy.getQualifiers()); + + // Finally perform an implicit address space cast + ArgExprs[Idx] = ImpCastExprToType(ArgExprs[Idx], NewArgTy, + CK_AddressSpaceConversion) + .get(); + } + } } if (Context.isDependenceAllowed() && @@ -6552,13 +7374,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, llvm::any_of(ArgExprs, [](clang::Expr *E) { return E->containsErrors(); })) && "should only occur in error-recovery path."); - QualType ReturnType = - llvm::isa_and_nonnull<FunctionDecl>(NDecl) - ? cast<FunctionDecl>(NDecl)->getCallResultType() - : Context.DependentTy; - return CallExpr::Create(Context, Fn, ArgExprs, ReturnType, - Expr::getValueKindForType(ReturnType), RParenLoc, - CurFPFeatureOverrides()); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, + VK_PRValue, RParenLoc, CurFPFeatureOverrides()); } return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc, ExecConfig, IsExecConfig); @@ -6662,11 +7479,18 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; } } - if (Caller->hasAttr<AnyX86InterruptAttr>() && - ((!FDecl || !FDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()))) { - Diag(Fn->getExprLoc(), diag::warn_anyx86_interrupt_regsave); - if (FDecl) - Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; + if (Caller->hasAttr<AnyX86InterruptAttr>() || + Caller->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) { + const TargetInfo &TI = Context.getTargetInfo(); + bool HasNonGPRRegisters = + TI.hasFeature("sse") || TI.hasFeature("x87") || TI.hasFeature("mmx"); + if (HasNonGPRRegisters && + (!FDecl || !FDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())) { + Diag(Fn->getExprLoc(), diag::warn_anyx86_excessive_regsave) + << (Caller->hasAttr<AnyX86InterruptAttr>() ? 0 : 1); + if (FDecl) + Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; + } } } @@ -6756,7 +7580,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 @@ -6810,6 +7634,16 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, TheCall->setType(FuncT->getCallResultType(Context)); TheCall->setValueKind(Expr::getValueKindForType(FuncT->getReturnType())); + // WebAssembly tables can't be used as arguments. + if (Context.getTargetInfo().getTriple().isWasm()) { + for (const Expr *Arg : Args) { + if (Arg && Arg->getType()->isWebAssemblyTableType()) { + return ExprError(Diag(Arg->getExprLoc(), + diag::err_wasm_table_as_function_parameter)); + } + } + } + if (Proto) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc, IsExecConfig)) @@ -6834,6 +7668,23 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, Proto = FDecl->getType()->getAs<FunctionProtoType>(); } + // If we still haven't found a prototype to use but there are arguments to + // the call, diagnose this as calling a function without a prototype. + // However, if we found a function declaration, check to see if + // -Wdeprecated-non-prototype was disabled where the function was declared. + // If so, we will silence the diagnostic here on the assumption that this + // interface is intentional and the user knows what they're doing. We will + // also silence the diagnostic if there is a function declaration but it + // was implicitly defined (the user already gets diagnostics about the + // creation of the implicit function declaration, so the additional warning + // is not helpful). + if (!Proto && !Args.empty() && + (!FDecl || (!FDecl->isImplicit() && + !Diags.isIgnored(diag::warn_strict_uses_without_prototype, + FDecl->getLocation())))) + Diag(LParenLoc, diag::warn_strict_uses_without_prototype) + << (FDecl != nullptr) << FDecl; + // Promote the arguments (C99 6.5.2.2p6). for (unsigned i = 0, e = Args.size(); i != e; i++) { Expr *Arg = Args[i]; @@ -6867,9 +7718,9 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, } if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl)) - if (!Method->isStatic()) + if (Method->isImplicitObjectMemberFunction()) return ExprError(Diag(LParenLoc, diag::err_member_call_without_object) - << Fn->getSourceRange()); + << Fn->getSourceRange() << 0); // Check for sentinels if (NDecl) @@ -6933,10 +7784,23 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) { - if (!tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, - diag::err_variable_object_no_init)) { + // C23 6.7.10p4: An entity of variable length array type shall not be + // initialized except by an empty initializer. + // + // The C extension warnings are issued from ParseBraceInitializer() and + // do not need to be issued here. However, we continue to issue an error + // in the case there are initializers or we are compiling C++. We allow + // use of VLAs in C++, but it's not clear we want to allow {} to zero + // init a VLA in C++ in all cases (such as with non-trivial constructors). + // FIXME: should we allow this construct in C++ when it makes sense to do + // so? + std::optional<unsigned> NumInits; + if (const auto *ILE = dyn_cast<InitListExpr>(LiteralExpr)) + NumInits = ILE->getNumInits(); + if ((LangOpts.CPlusPlus || NumInits.value_or(0)) && + !tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, + diag::err_variable_object_no_init)) return ExprError(); - } } } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, @@ -7394,12 +8258,32 @@ bool Sema::isValidSveBitcast(QualType srcTy, QualType destTy) { assert(srcTy->isVectorType() || destTy->isVectorType()); auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { - if (!FirstType->isSizelessBuiltinType()) + if (!FirstType->isSVESizelessBuiltinType()) return false; const auto *VecTy = SecondType->getAs<VectorType>(); - return VecTy && - VecTy->getVectorKind() == VectorType::SveFixedLengthDataVector; + return VecTy && VecTy->getVectorKind() == VectorKind::SveFixedLengthData; + }; + + return ValidScalableConversion(srcTy, destTy) || + ValidScalableConversion(destTy, srcTy); +} + +/// Are the two types RVV-bitcast-compatible types? I.e. is bitcasting from the +/// first RVV type (e.g. an RVV scalable type) to the second type (e.g. an RVV +/// VLS type) allowed? +/// +/// This will also return false if the two given types do not make sense from +/// the perspective of RVV bitcasts. +bool Sema::isValidRVVBitcast(QualType srcTy, QualType destTy) { + assert(srcTy->isVectorType() || destTy->isVectorType()); + + auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { + if (!FirstType->isRVVSizelessBuiltinType()) + return false; + + const auto *VecTy = SecondType->getAs<VectorType>(); + return VecTy && VecTy->getVectorKind() == VectorKind::RVVFixedLengthData; }; return ValidScalableConversion(srcTy, destTy) || @@ -7438,6 +8322,30 @@ bool Sema::areVectorTypesSameSize(QualType SrcTy, QualType DestTy) { return (SrcLen * SrcEltSize == DestLen * DestEltSize); } +// This returns true if at least one of the types is an altivec vector. +bool Sema::anyAltivecTypes(QualType SrcTy, QualType DestTy) { + assert((DestTy->isVectorType() || SrcTy->isVectorType()) && + "expected at least one type to be a vector here"); + + bool IsSrcTyAltivec = + SrcTy->isVectorType() && ((SrcTy->castAs<VectorType>()->getVectorKind() == + VectorKind::AltiVecVector) || + (SrcTy->castAs<VectorType>()->getVectorKind() == + VectorKind::AltiVecBool) || + (SrcTy->castAs<VectorType>()->getVectorKind() == + VectorKind::AltiVecPixel)); + + bool IsDestTyAltivec = DestTy->isVectorType() && + ((DestTy->castAs<VectorType>()->getVectorKind() == + VectorKind::AltiVecVector) || + (DestTy->castAs<VectorType>()->getVectorKind() == + VectorKind::AltiVecBool) || + (DestTy->castAs<VectorType>()->getVectorKind() == + VectorKind::AltiVecPixel)); + + return (IsSrcTyAltivec || IsDestTyAltivec); +} + /// Are the two types lax-compatible vector types? That is, given /// that one of them is a vector, do they have equal storage sizes, /// where the storage size is the number of elements times the element @@ -7659,8 +8567,7 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, CastExpr = Result.get(); } - if (getLangOpts().CPlusPlus && !castType->isVoidType() && - !getSourceManager().isInSystemMacro(LParenLoc)) + if (getLangOpts().CPlusPlus && !castType->isVoidType()) Diag(LParenLoc, diag::warn_old_style_cast) << CastExpr->getSourceRange(); CheckTollFreeBridgeCast(castType, CastExpr); @@ -7706,6 +8613,9 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, // initializers must be one or must match the size of the vector. // If a single value is specified in the initializer then it will be // replicated to all the components of the vector + if (CheckAltivecInitFromScalar(E->getSourceRange(), Ty, + VTy->getElementType())) + return ExprError(); if (ShouldSplatAltivecScalarInCast(VTy)) { // The number of initializers must be one or must match the size of the // vector. If a single value is specified in the initializer then it will @@ -7730,16 +8640,15 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, else { // For OpenCL, when the number of initializers is a single value, // it will be replicated to all components of the vector. - if (getLangOpts().OpenCL && - VTy->getVectorKind() == VectorType::GenericVector && + if (getLangOpts().OpenCL && VTy->getVectorKind() == VectorKind::Generic && numExprs == 1) { - QualType ElemTy = VTy->getElementType(); - ExprResult Literal = DefaultLvalueConversion(exprs[0]); - if (Literal.isInvalid()) - return ExprError(); - Literal = ImpCastExprToType(Literal.get(), ElemTy, - PrepareScalarCast(Literal, ElemTy)); - return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get()); + QualType ElemTy = VTy->getElementType(); + ExprResult Literal = DefaultLvalueConversion(exprs[0]); + if (Literal.isInvalid()) + return ExprError(); + Literal = ImpCastExprToType(Literal.get(), ElemTy, + PrepareScalarCast(Literal, ElemTy)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get()); } initExprs.append(exprs, exprs + numExprs); @@ -7780,10 +8689,10 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L, /// Emit a specialized diagnostic when one expression is a null pointer /// constant and the other is not a pointer. Returns true if a diagnostic is /// emitted. -bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, +bool Sema::DiagnoseConditionalForNull(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation QuestionLoc) { - Expr *NullExpr = LHSExpr; - Expr *NonPointerExpr = RHSExpr; + const Expr *NullExpr = LHSExpr; + const Expr *NonPointerExpr = RHSExpr; Expr::NullPointerConstantKind NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); @@ -7819,7 +8728,8 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, } /// Return false if the condition expression is valid, true otherwise. -static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { +static bool checkCondition(Sema &S, const Expr *Cond, + SourceLocation QuestionLoc) { QualType CondTy = Cond->getType(); // OpenCL v1.1 s6.3.i says the condition cannot be a floating point type. @@ -7837,23 +8747,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, @@ -7877,7 +8770,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; @@ -7947,7 +8840,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 @@ -8245,11 +9140,17 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, // result as specified in OpenCL v1.1 s6.3.i. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc, - /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); - if (VecResTy.isNull()) return QualType(); + bool IsBoolVecLang = + !S.getLangOpts().OpenCL && !S.getLangOpts().OpenCLCPlusPlus; + QualType VecResTy = + S.CheckVectorOperands(LHS, RHS, QuestionLoc, + /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ IsBoolVecLang, + /*ReportInvalid*/ true); + if (VecResTy.isNull()) + return QualType(); // The result type must match the condition type as specified in // OpenCL v1.1 s6.11.6. if (checkVectorResult(S, CondTy, VecResTy, QuestionLoc)) @@ -8319,23 +9220,31 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (checkCondition(*this, Cond.get(), QuestionLoc)) return QualType(); - // Now check the two expressions. + // Handle vectors. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) - return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); + // WebAssembly tables are not allowed as conditional LHS or RHS. QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); + if (LHSTy->isWebAssemblyTableType() || RHSTy->isWebAssemblyTableType()) { + Diag(QuestionLoc, diag::err_wasm_table_conditional_expression) + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } - // Diagnose attempts to convert between __float128 and long double where - // such conversions currently can't be handled. + // Diagnose attempts to convert between __ibm128, __float128 and long double + // where such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy @@ -8346,16 +9255,17 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary // selection operator (?:). if (getLangOpts().OpenCL && - (checkBlockType(*this, LHS.get()) | checkBlockType(*this, RHS.get()))) { + ((int)checkBlockType(*this, LHS.get()) | (int)checkBlockType(*this, RHS.get()))) { return QualType(); } // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { - // Disallow invalid arithmetic conversions, such as those between ExtInts of - // different sizes, or between ExtInts and other types. - if (ResTy.isNull() && (LHSTy->isExtIntType() || RHSTy->isExtIntType())) { + // Disallow invalid arithmetic conversions, such as those between bit- + // precise integers types of different sizes, or between a bit-precise + // integer and another type. + if (ResTy.isNull() && (LHSTy->isBitIntType() || RHSTy->isBitIntType())) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); @@ -8368,11 +9278,6 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return ResTy; } - // And if they're both bfloat (which isn't arithmetic), that's fine too. - if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) { - return LHSTy; - } - // If both operands are the same structure or union type, the result is that // type. if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3 @@ -8380,16 +9285,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; } + // C23 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; @@ -8423,17 +9349,17 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, /*IsIntFirstExpr=*/false)) return LHSTy; - // Allow ?: operations in which both operands have the same - // built-in sizeless type. - if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy)) - return LHSTy; - // 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 // likely forgot to take the address of the other expression. if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); + // Finally, if the LHS and RHS types are canonically the same type, we can + // use the common sugared type. + if (Context.hasSameType(LHSTy, RHSTy)) + return Context.getCommonSugaredType(LHSTy, RHSTy); + // Otherwise, the operands are not compatible. Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() @@ -8615,28 +9541,27 @@ static bool IsArithmeticOp(BinaryOperatorKind Opc) { /// expression, either using a built-in or overloaded operator, /// and sets *OpCode to the opcode and *RHSExprs to the right-hand side /// expression. -static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, - Expr **RHSExprs) { +static bool IsArithmeticBinaryExpr(const Expr *E, BinaryOperatorKind *Opcode, + const Expr **RHSExprs) { // Don't strip parenthesis: we should not warn if E is in parenthesis. E = E->IgnoreImpCasts(); E = E->IgnoreConversionOperatorSingleStep(); E = E->IgnoreImpCasts(); - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) { + if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) { E = MTE->getSubExpr(); E = E->IgnoreImpCasts(); } // Built-in binary operator. - if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) { - if (IsArithmeticOp(OP->getOpcode())) { - *Opcode = OP->getOpcode(); - *RHSExprs = OP->getRHS(); - return true; - } + if (const auto *OP = dyn_cast<BinaryOperator>(E); + OP && IsArithmeticOp(OP->getOpcode())) { + *Opcode = OP->getOpcode(); + *RHSExprs = OP->getRHS(); + return true; } // Overloaded operator. - if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(E)) { + if (const auto *Call = dyn_cast<CXXOperatorCallExpr>(E)) { if (Call->getNumArgs() != 2) return false; @@ -8661,14 +9586,14 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, /// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type /// or is a logical expression such as (x==y) which has int type, but is /// commonly interpreted as boolean. -static bool ExprLooksBoolean(Expr *E) { +static bool ExprLooksBoolean(const Expr *E) { E = E->IgnoreParenImpCasts(); if (E->getType()->isBooleanType()) return true; - if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) + if (const auto *OP = dyn_cast<BinaryOperator>(E)) return OP->isComparisonOp() || OP->isLogicalOp(); - if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E)) + if (const auto *OP = dyn_cast<UnaryOperator>(E)) return OP->getOpcode() == UO_LNot; if (E->getType()->isPointerType()) return true; @@ -8682,13 +9607,11 @@ static bool ExprLooksBoolean(Expr *E) { /// and binary operator are mixed in a way that suggests the programmer assumed /// the conditional operator has higher precedence, for example: /// "int x = a + someBinaryCondition ? 1 : 2". -static void DiagnoseConditionalPrecedence(Sema &Self, - SourceLocation OpLoc, - Expr *Condition, - Expr *LHSExpr, - Expr *RHSExpr) { +static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc, + Expr *Condition, const Expr *LHSExpr, + const Expr *RHSExpr) { BinaryOperatorKind CondOpcode; - Expr *CondRHS; + const Expr *CondRHS; if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS)) return; @@ -8724,8 +9647,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) @@ -8762,7 +9685,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. @@ -8875,6 +9798,21 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, ColonLoc, result, VK, OK); } +// Check that the SME attributes for PSTATE.ZA and PSTATE.SM are compatible. +bool Sema::IsInvalidSMECallConversion(QualType FromType, QualType ToType) { + unsigned FromAttributes = 0, ToAttributes = 0; + if (const auto *FromFn = + dyn_cast<FunctionProtoType>(Context.getCanonicalType(FromType))) + FromAttributes = + FromFn->getAArch64SMEAttributes() & FunctionType::SME_AttributeMask; + if (const auto *ToFn = + dyn_cast<FunctionProtoType>(Context.getCanonicalType(ToType))) + ToAttributes = + ToFn->getAArch64SMEAttributes() & FunctionType::SME_AttributeMask; + + return FromAttributes != ToAttributes; +} + // Check if we have a conversion between incompatible cmse function pointer // types, that is, a conversion between a function pointer with the // cmse_nonsecure_call attribute and one without. @@ -8899,7 +9837,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!"); @@ -8968,6 +9907,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); @@ -9033,6 +9979,8 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { return Sema::IncompatibleFunctionPointer; if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans)) return Sema::IncompatibleFunctionPointer; + if (S.IsInvalidSMECallConversion(rtrans, ltrans)) + return Sema::IncompatibleFunctionPointer; return ConvTy; } @@ -9181,6 +10129,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Compatible; } + // If the LHS has an __auto_type, there are no additional type constraints + // to be worried about. + if (const auto *AT = dyn_cast<AutoType>(LHSType)) { + if (AT->isGNUAutoType()) { + Kind = CK_NoOp; + return Compatible; + } + } + // If we have an atomic type, try a non-atomic assignment, then just add an // atomic qualification step. if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(LHSType)) { @@ -9237,6 +10194,14 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // vectors, the total size only needs to be the same. This is a bitcast; // no bits are changed but the result type is different. if (isLaxVectorConversion(RHSType, LHSType)) { + // The default for lax vector conversions with Altivec vectors will + // change, so if we are converting between vector types where + // at least one is an Altivec vector, emit a warning. + if (Context.getTargetInfo().getTriple().isPPC() && + anyAltivecTypes(RHSType, LHSType) && + !Context.areCompatibleVectorTypes(RHSType, LHSType)) + Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all) + << RHSType << LHSType; Kind = CK_BitCast; return IncompatibleVectors; } @@ -9250,6 +10215,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, const VectorType *VecType = RHSType->getAs<VectorType>(); if (VecType && VecType->getNumElements() == 1 && isLaxVectorConversion(RHSType, LHSType)) { + if (Context.getTargetInfo().getTriple().isPPC() && + (VecType->getVectorKind() == VectorKind::AltiVecVector || + VecType->getVectorKind() == VectorKind::AltiVecBool || + VecType->getVectorKind() == VectorKind::AltiVecPixel)) + Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all) + << RHSType << LHSType; ExprResult *VecExpr = &RHS; *VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast); Kind = CK_BitCast; @@ -9258,19 +10229,29 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Allow assignments between fixed-length and sizeless SVE vectors. - if ((LHSType->isSizelessBuiltinType() && RHSType->isVectorType()) || - (LHSType->isVectorType() && RHSType->isSizelessBuiltinType())) + if ((LHSType->isSVESizelessBuiltinType() && RHSType->isVectorType()) || + (LHSType->isVectorType() && RHSType->isSVESizelessBuiltinType())) if (Context.areCompatibleSveTypes(LHSType, RHSType) || Context.areLaxCompatibleSveTypes(LHSType, RHSType)) { Kind = CK_BitCast; return Compatible; } + // Allow assignments between fixed-length and sizeless RVV vectors. + if ((LHSType->isRVVSizelessBuiltinType() && RHSType->isVectorType()) || + (LHSType->isVectorType() && RHSType->isRVVSizelessBuiltinType())) { + if (Context.areCompatibleRVVTypes(LHSType, RHSType) || + Context.areLaxCompatibleRVVTypes(LHSType, RHSType)) { + Kind = CK_BitCast; + return Compatible; + } + } + return Incompatible; } - // Diagnose attempts to convert between __float128 and long double where - // such conversions currently can't be handled. + // Diagnose attempts to convert between __ibm128, __float128 and long double + // where such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return Incompatible; @@ -9300,7 +10281,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* @@ -9434,6 +10416,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } + // Conversion to nullptr_t (C23 only) + if (getLangOpts().C23 && LHSType->isNullPtrType() && + RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { + // null -> nullptr_t + Kind = CK_NullToPointer; + return Compatible; + } + // Conversions from pointers that are not covered by the above. if (isa<PointerType>(RHSType)) { // T* -> _Bool @@ -9628,12 +10619,36 @@ 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; + } + + // The constraints are expressed in terms of the atomic, qualified, or + // unqualified type of the LHS. + QualType LHSTypeAfterConversion = LHSType.getAtomicUnqualifiedType(); + // C99 6.5.16.1p1: the left operand is a pointer and the right is - // a null pointer constant. - if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() || - LHSType->isBlockPointerType()) && - RHS.get()->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { + // a null pointer constant <C23>or its type is nullptr_t;</C23>. + if ((LHSTypeAfterConversion->isPointerType() || + LHSTypeAfterConversion->isObjCObjectPointerType() || + LHSTypeAfterConversion->isBlockPointerType()) && + ((getLangOpts().C23 && RHS.get()->getType()->isNullPtrType()) || + RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull))) { if (Diagnose || ConvertRHS) { CastKind Kind; CXXCastPath Path; @@ -9644,6 +10659,26 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, } return Compatible; } + // C23 6.5.16.1p1: the left operand has type atomic, qualified, or + // unqualified bool, and the right operand is a pointer or its type is + // nullptr_t. + if (getLangOpts().C23 && LHSType->isBooleanType() && + RHS.get()->getType()->isNullPtrType()) { + // NB: T* -> _Bool is handled in CheckAssignmentConstraints, this only + // only handles nullptr -> _Bool due to needing an extra conversion + // step. + // We model this by converting from nullptr -> void * and then let the + // conversion from void * -> _Bool happen naturally. + if (Diagnose || ConvertRHS) { + CastKind Kind; + CXXCastPath Path; + CheckPointerConversion(RHS.get(), Context.VoidPtrTy, Kind, Path, + /*IgnoreBaseAccess=*/false, Diagnose); + if (ConvertRHS) + RHS = ImpCastExprToType(RHS.get(), Context.VoidPtrTy, Kind, VK_PRValue, + &Path); + } + } // OpenCL queue_t type assignment. if (LHSType->isQueueT() && RHS.get()->isNullPointerConstant( @@ -9652,18 +10687,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); @@ -9842,9 +10865,11 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, 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()); + QualType NewVecTy = + VecTy->isExtVectorType() + ? S.Context.getExtVectorType(ElementType, VecTy->getNumElements()) + : S.Context.getVectorType(ElementType, VecTy->getNumElements(), + VecTy->getVectorKind()); // Look through the implicit cast. Return the subexpression if its type is // NewVecTy. @@ -9876,7 +10901,7 @@ static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, // bits that the vector element type, reject it. llvm::APSInt Result = EVResult.Val.getInt(); unsigned NumBits = IntSigned - ? (Result.isNegative() ? Result.getMinSignedBits() + ? (Result.isNegative() ? Result.getSignificantBits() : Result.getActiveBits()) : Result.getActiveBits(); if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits) @@ -9944,12 +10969,18 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, ExprResult *Vector) { QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType(); QualType VectorTy = Vector->get()->getType().getUnqualifiedType(); - const VectorType *VT = VectorTy->getAs<VectorType>(); - - assert(!isa<ExtVectorType>(VT) && - "ExtVectorTypes should not be handled here!"); - - QualType VectorEltTy = VT->getElementType(); + QualType VectorEltTy; + + if (const auto *VT = VectorTy->getAs<VectorType>()) { + assert(!isa<ExtVectorType>(VT) && + "ExtVectorTypes should not be handled here!"); + VectorEltTy = VT->getElementType(); + } else if (VectorTy->isSveVLSBuiltinType()) { + VectorEltTy = + VectorTy->castAs<BuiltinType>()->getSveEltType(S.getASTContext()); + } else { + llvm_unreachable("Only Fixed-Length and SVE Vector types are handled here"); + } // Reject cases where the vector element type or the scalar element type are // not integral or floating point types. @@ -10020,18 +11051,18 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, return true; // Adjust scalar if desired. - if (Scalar) { - if (ScalarCast != CK_NoOp) - *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); - *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); - } + if (ScalarCast != CK_NoOp) + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); return false; } QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, - bool AllowBoolConversions) { + bool AllowBoolConversions, + bool AllowBoolOperation, + bool ReportInvalid) { if (!IsCompAssign) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); if (LHS.isInvalid()) @@ -10050,20 +11081,21 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, const VectorType *RHSVecType = RHSType->getAs<VectorType>(); assert(LHSVecType || RHSVecType); - if ((LHSVecType && LHSVecType->getElementType()->isBFloat16Type()) || - (RHSVecType && RHSVecType->getElementType()->isBFloat16Type())) - return InvalidOperands(Loc, LHS, RHS); - // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. - if (!AllowBothBool && - LHSVecType && LHSVecType->getVectorKind() == VectorType::AltiVecBool && - RHSVecType && RHSVecType->getVectorKind() == VectorType::AltiVecBool) - return InvalidOperands(Loc, LHS, RHS); + if (!AllowBothBool && LHSVecType && + LHSVecType->getVectorKind() == VectorKind::AltiVecBool && RHSVecType && + RHSVecType->getVectorKind() == VectorKind::AltiVecBool) + return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); + + // This operation may not be performed on boolean vectors. + if (!AllowBoolOperation && + (LHSType->isExtVectorBoolType() || RHSType->isExtVectorBoolType())) + return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); // 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 && @@ -10085,56 +11117,89 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, LHSVecType->getNumElements() == RHSVecType->getNumElements() && (Context.getTypeSize(LHSVecType->getElementType()) == Context.getTypeSize(RHSVecType->getElementType()))) { - if (LHSVecType->getVectorKind() == VectorType::AltiVecVector && + if (LHSVecType->getVectorKind() == VectorKind::AltiVecVector && LHSVecType->getElementType()->isIntegerType() && - RHSVecType->getVectorKind() == VectorType::AltiVecBool) { + RHSVecType->getVectorKind() == VectorKind::AltiVecBool) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return LHSType; } if (!IsCompAssign && - LHSVecType->getVectorKind() == VectorType::AltiVecBool && - RHSVecType->getVectorKind() == VectorType::AltiVecVector && + LHSVecType->getVectorKind() == VectorKind::AltiVecBool && + RHSVecType->getVectorKind() == VectorKind::AltiVecVector && RHSVecType->getElementType()->isIntegerType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast); return RHSType; } } - // Expressions containing fixed-length and sizeless SVE vectors are invalid - // since the ambiguity can affect the ABI. - auto IsSveConversion = [](QualType FirstType, QualType SecondType) { + // Expressions containing fixed-length and sizeless SVE/RVV vectors are + // invalid since the ambiguity can affect the ABI. + auto IsSveRVVConversion = [](QualType FirstType, QualType SecondType, + unsigned &SVEorRVV) { const VectorType *VecType = SecondType->getAs<VectorType>(); - return FirstType->isSizelessBuiltinType() && VecType && - (VecType->getVectorKind() == VectorType::SveFixedLengthDataVector || - VecType->getVectorKind() == - VectorType::SveFixedLengthPredicateVector); + SVEorRVV = 0; + if (FirstType->isSizelessBuiltinType() && VecType) { + if (VecType->getVectorKind() == VectorKind::SveFixedLengthData || + VecType->getVectorKind() == VectorKind::SveFixedLengthPredicate) + return true; + if (VecType->getVectorKind() == VectorKind::RVVFixedLengthData || + VecType->getVectorKind() == VectorKind::RVVFixedLengthMask) { + SVEorRVV = 1; + return true; + } + } + + return false; }; - if (IsSveConversion(LHSType, RHSType) || IsSveConversion(RHSType, LHSType)) { - Diag(Loc, diag::err_typecheck_sve_ambiguous) << LHSType << RHSType; + unsigned SVEorRVV; + if (IsSveRVVConversion(LHSType, RHSType, SVEorRVV) || + IsSveRVVConversion(RHSType, LHSType, SVEorRVV)) { + Diag(Loc, diag::err_typecheck_sve_rvv_ambiguous) + << SVEorRVV << LHSType << RHSType; return QualType(); } - // Expressions containing GNU and SVE (fixed or sizeless) vectors are invalid - // since the ambiguity can affect the ABI. - auto IsSveGnuConversion = [](QualType FirstType, QualType SecondType) { + // Expressions containing GNU and SVE or RVV (fixed or sizeless) vectors are + // invalid since the ambiguity can affect the ABI. + auto IsSveRVVGnuConversion = [](QualType FirstType, QualType SecondType, + unsigned &SVEorRVV) { const VectorType *FirstVecType = FirstType->getAs<VectorType>(); const VectorType *SecondVecType = SecondType->getAs<VectorType>(); - if (FirstVecType && SecondVecType) - return FirstVecType->getVectorKind() == VectorType::GenericVector && - (SecondVecType->getVectorKind() == - VectorType::SveFixedLengthDataVector || - SecondVecType->getVectorKind() == - VectorType::SveFixedLengthPredicateVector); + SVEorRVV = 0; + if (FirstVecType && SecondVecType) { + if (FirstVecType->getVectorKind() == VectorKind::Generic) { + if (SecondVecType->getVectorKind() == VectorKind::SveFixedLengthData || + SecondVecType->getVectorKind() == + VectorKind::SveFixedLengthPredicate) + return true; + if (SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthData || + SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthMask) { + SVEorRVV = 1; + return true; + } + } + return false; + } + + if (SecondVecType && + SecondVecType->getVectorKind() == VectorKind::Generic) { + if (FirstType->isSVESizelessBuiltinType()) + return true; + if (FirstType->isRVVSizelessBuiltinType()) { + SVEorRVV = 1; + return true; + } + } - return FirstType->isSizelessBuiltinType() && SecondVecType && - SecondVecType->getVectorKind() == VectorType::GenericVector; + return false; }; - if (IsSveGnuConversion(LHSType, RHSType) || - IsSveGnuConversion(RHSType, LHSType)) { - Diag(Loc, diag::err_typecheck_sve_gnu_ambiguous) << LHSType << RHSType; + if (IsSveRVVGnuConversion(LHSType, RHSType, SVEorRVV) || + IsSveRVVGnuConversion(RHSType, LHSType, SVEorRVV)) { + Diag(Loc, diag::err_typecheck_sve_rvv_gnu_ambiguous) + << SVEorRVV << LHSType << RHSType; return QualType(); } @@ -10173,6 +11238,10 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, QualType OtherType = LHSVecType ? RHSType : LHSType; ExprResult *OtherExpr = LHSVecType ? &RHS : &LHS; if (isLaxVectorConversion(OtherType, VecType)) { + if (Context.getTargetInfo().getTriple().isPPC() && + anyAltivecTypes(RHSType, LHSType) && + !Context.areCompatibleVectorTypes(RHSType, LHSType)) + Diag(Loc, diag::warn_deprecated_lax_vec_conv_all) << RHSType << LHSType; // If we're allowing lax vector conversions, only the total (data) size // needs to be the same. For non compound assignment, if one of the types is // scalar, the result is always the vector type. @@ -10238,6 +11307,81 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, return QualType(); } +QualType Sema::CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + bool IsCompAssign, + ArithConvKind OperationKind) { + if (!IsCompAssign) { + LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + } + RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); + if (RHS.isInvalid()) + return QualType(); + + QualType LHSType = LHS.get()->getType().getUnqualifiedType(); + QualType RHSType = RHS.get()->getType().getUnqualifiedType(); + + const BuiltinType *LHSBuiltinTy = LHSType->getAs<BuiltinType>(); + const BuiltinType *RHSBuiltinTy = RHSType->getAs<BuiltinType>(); + + unsigned DiagID = diag::err_typecheck_invalid_operands; + if ((OperationKind == ACK_Arithmetic) && + ((LHSBuiltinTy && LHSBuiltinTy->isSVEBool()) || + (RHSBuiltinTy && RHSBuiltinTy->isSVEBool()))) { + Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + if (Context.hasSameType(LHSType, RHSType)) + return LHSType; + + if (LHSType->isSveVLSBuiltinType() && !RHSType->isSveVLSBuiltinType()) { + if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS)) + return LHSType; + } + if (RHSType->isSveVLSBuiltinType() && !LHSType->isSveVLSBuiltinType()) { + if (LHS.get()->isLValue() || + !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS)) + return RHSType; + } + + if ((!LHSType->isSveVLSBuiltinType() && !LHSType->isRealType()) || + (!RHSType->isSveVLSBuiltinType() && !RHSType->isRealType())) { + Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar) + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + if (LHSType->isSveVLSBuiltinType() && RHSType->isSveVLSBuiltinType() && + Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC != + Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC) { + Diag(Loc, diag::err_typecheck_vector_lengths_not_equal) + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + if (LHSType->isSveVLSBuiltinType() || RHSType->isSveVLSBuiltinType()) { + QualType Scalar = LHSType->isSveVLSBuiltinType() ? RHSType : LHSType; + QualType Vector = LHSType->isSveVLSBuiltinType() ? LHSType : RHSType; + bool ScalarOrVector = + LHSType->isSveVLSBuiltinType() && RHSType->isSveVLSBuiltinType(); + + Diag(Loc, diag::err_typecheck_vector_not_convertable_implict_truncation) + << ScalarOrVector << Scalar << Vector; + + return QualType(); + } + + Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); +} + // checkArithmeticNull - Detect when a NULL constant is used improperly in an // expression. These are mainly cases where the null pointer is used as an // integer instead of a pointer. @@ -10347,8 +11491,13 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, QualType RHSTy = RHS.get()->getType(); if (LHSTy->isVectorType() || RHSTy->isVectorType()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/false); + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); + if (LHSTy->isSveVLSBuiltinType() || RHSTy->isSveVLSBuiltinType()) + return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, + ACK_Arithmetic); if (!IsDiv && (LHSTy->isConstantMatrixType() || RHSTy->isConstantMatrixType())) return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign); @@ -10381,8 +11530,20 @@ QualType Sema::CheckRemainderOperands( if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/false); + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); + return InvalidOperands(Loc, LHS, RHS); + } + + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, + ACK_Arithmetic); + return InvalidOperands(Loc, LHS, RHS); } @@ -10443,8 +11604,10 @@ static void diagnoseSubtractionOnNullPointer(Sema &S, SourceLocation Loc, if (S.Diags.getSuppressSystemWarnings() && S.SourceMgr.isInSystemMacro(Loc)) return; - S.Diag(Loc, diag::warn_pointer_sub_null_ptr) - << S.getLangOpts().CPlusPlus << Pointer->getSourceRange(); + S.DiagRuntimeBehavior(Loc, Pointer, + S.PDiag(diag::warn_pointer_sub_null_ptr) + << S.getLangOpts().CPlusPlus + << Pointer->getSourceRange()); } /// Diagnose invalid arithmetic on two function pointers. @@ -10683,14 +11846,25 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands( - LHS, RHS, Loc, CompLHSTy, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/getLangOpts().ZVector); + QualType compType = + CheckVectorOperands(LHS, RHS, Loc, CompLHSTy, + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); if (CompLHSTy) *CompLHSTy = compType; return compType; } + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) { + QualType compType = + CheckSizelessVectorOperands(LHS, RHS, Loc, CompLHSTy, ACK_Arithmetic); + if (CompLHSTy) + *CompLHSTy = compType; + return compType; + } + if (LHS.get()->getType()->isConstantMatrixType() || RHS.get()->getType()->isConstantMatrixType()) { QualType compType = @@ -10770,7 +11944,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; @@ -10787,14 +11961,25 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands( - LHS, RHS, Loc, CompLHSTy, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/getLangOpts().ZVector); + QualType compType = + CheckVectorOperands(LHS, RHS, Loc, CompLHSTy, + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); if (CompLHSTy) *CompLHSTy = compType; return compType; } + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) { + QualType compType = + CheckSizelessVectorOperands(LHS, RHS, Loc, CompLHSTy, ACK_Arithmetic); + if (CompLHSTy) + *CompLHSTy = compType; + return compType; + } + if (LHS.get()->getType()->isConstantMatrixType() || RHS.get()->getType()->isConstantMatrixType()) { QualType compType = @@ -10939,14 +12124,13 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, QualType LHSExprType = LHS.get()->getType(); uint64_t LeftSize = S.Context.getTypeSize(LHSExprType); - if (LHSExprType->isExtIntType()) + if (LHSExprType->isBitIntType()) LeftSize = S.Context.getIntWidth(LHSExprType); else if (LHSExprType->isFixedPointType()) { auto FXSema = S.Context.getFixedPointSemantics(LHSExprType); LeftSize = FXSema.getWidth() - (unsigned)FXSema.hasUnsignedPadding(); } - llvm::APInt LeftBits(Right.getBitWidth(), LeftSize); - if (Right.uge(LeftBits)) { + if (Right.uge(LeftSize)) { S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_gt_typewidth) << RHS.get()->getSourceRange()); @@ -10970,10 +12154,16 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, return; llvm::APSInt Left = LHSResult.Val.getInt(); - // If LHS does not have a signed type and non-negative value - // then, the behavior is undefined before C++2a. Warn about it. - if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined() && - !S.getLangOpts().CPlusPlus20) { + // Don't warn if signed overflow is defined, then all the rest of the + // diagnostics will not be triggered because the behavior is defined. + // Also don't warn in C++20 mode (and newer), as signed left shifts + // always wrap and never overflow. + if (S.getLangOpts().isSignedOverflowDefined() || S.getLangOpts().CPlusPlus20) + return; + + // If LHS does not have a non-negative value then, the + // behavior is undefined before C++2a. Warn about it. + if (Left.isNegative()) { S.DiagRuntimeBehavior(Loc, LHS.get(), S.PDiag(diag::warn_shift_lhs_negative) << LHS.get()->getSourceRange()); @@ -10981,8 +12171,8 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, } llvm::APInt ResultBits = - static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits(); - if (LeftBits.uge(ResultBits)) + static_cast<llvm::APInt &>(Right) + Left.getSignificantBits(); + if (ResultBits.ule(LeftSize)) return; llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue()); Result = Result.shl(Right); @@ -10996,7 +12186,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, // bugs -- if the result is cast back to an unsigned type, it will have the // expected value. Thus we place this behind a different warning that can be // turned off separately if needed. - if (LeftBits == ResultBits - 1) { + if (ResultBits - 1 == LeftSize) { S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) << HexResult << LHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); @@ -11004,9 +12194,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) - << HexResult.str() << Result.getMinSignedBits() << LHSType - << Left.getBitWidth() << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); + << HexResult.str() << Result.getSignificantBits() << LHSType + << Left.getBitWidth() << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } /// Return the resulting type when a vector is shifted @@ -11041,6 +12231,15 @@ static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS, const VectorType *RHSVecTy = RHSType->getAs<VectorType>(); QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType; + // Do not allow shifts for boolean vectors. + if ((LHSVecTy && LHSVecTy->isExtVectorBoolType()) || + (RHSVecTy && RHSVecTy->isExtVectorBoolType())) { + S.Diag(Loc, diag::err_typecheck_invalid_operands) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange(); + return QualType(); + } + // The operands need to be integers. if (!LHSEleType->isIntegerType()) { S.Diag(Loc, diag::err_typecheck_expect_int) @@ -11096,6 +12295,97 @@ static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS, return LHSType; } +static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS, + ExprResult &RHS, SourceLocation Loc, + bool IsCompAssign) { + if (!IsCompAssign) { + LHS = S.UsualUnaryConversions(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + } + + RHS = S.UsualUnaryConversions(RHS.get()); + if (RHS.isInvalid()) + return QualType(); + + QualType LHSType = LHS.get()->getType(); + const BuiltinType *LHSBuiltinTy = LHSType->castAs<BuiltinType>(); + QualType LHSEleType = LHSType->isSveVLSBuiltinType() + ? LHSBuiltinTy->getSveEltType(S.getASTContext()) + : LHSType; + + // Note that RHS might not be a vector + QualType RHSType = RHS.get()->getType(); + const BuiltinType *RHSBuiltinTy = RHSType->castAs<BuiltinType>(); + QualType RHSEleType = RHSType->isSveVLSBuiltinType() + ? RHSBuiltinTy->getSveEltType(S.getASTContext()) + : RHSType; + + if ((LHSBuiltinTy && LHSBuiltinTy->isSVEBool()) || + (RHSBuiltinTy && RHSBuiltinTy->isSVEBool())) { + S.Diag(Loc, diag::err_typecheck_invalid_operands) + << LHSType << RHSType << LHS.get()->getSourceRange(); + return QualType(); + } + + if (!LHSEleType->isIntegerType()) { + S.Diag(Loc, diag::err_typecheck_expect_int) + << LHS.get()->getType() << LHS.get()->getSourceRange(); + return QualType(); + } + + if (!RHSEleType->isIntegerType()) { + S.Diag(Loc, diag::err_typecheck_expect_int) + << RHS.get()->getType() << RHS.get()->getSourceRange(); + return QualType(); + } + + if (LHSType->isSveVLSBuiltinType() && RHSType->isSveVLSBuiltinType() && + (S.Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC != + S.Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC)) { + S.Diag(Loc, diag::err_typecheck_invalid_operands) + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + if (!LHSType->isSveVLSBuiltinType()) { + assert(RHSType->isSveVLSBuiltinType()); + if (IsCompAssign) + return RHSType; + if (LHSEleType != RHSEleType) { + LHS = S.ImpCastExprToType(LHS.get(), RHSEleType, clang::CK_IntegralCast); + LHSEleType = RHSEleType; + } + const llvm::ElementCount VecSize = + S.Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC; + QualType VecTy = + S.Context.getScalableVectorType(LHSEleType, VecSize.getKnownMinValue()); + LHS = S.ImpCastExprToType(LHS.get(), VecTy, clang::CK_VectorSplat); + LHSType = VecTy; + } else if (RHSBuiltinTy && RHSBuiltinTy->isSveVLSBuiltinType()) { + if (S.Context.getTypeSize(RHSBuiltinTy) != + S.Context.getTypeSize(LHSBuiltinTy)) { + S.Diag(Loc, diag::err_typecheck_vector_lengths_not_equal) + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + } else { + const llvm::ElementCount VecSize = + S.Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC; + if (LHSEleType != RHSEleType) { + RHS = S.ImpCastExprToType(RHS.get(), LHSEleType, clang::CK_IntegralCast); + RHSEleType = LHSEleType; + } + QualType VecTy = + S.Context.getScalableVectorType(RHSEleType, VecSize.getKnownMinValue()); + RHS = S.ImpCastExprToType(RHS.get(), VecTy, CK_VectorSplat); + } + + return LHSType; +} + // C99 6.5.7 QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, @@ -11110,15 +12400,19 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, // like general shifts, except that neither the LHS nor the RHS is // allowed to be a "vector bool". if (auto LHSVecType = LHS.get()->getType()->getAs<VectorType>()) - if (LHSVecType->getVectorKind() == VectorType::AltiVecBool) + if (LHSVecType->getVectorKind() == VectorKind::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); if (auto RHSVecType = RHS.get()->getType()->getAs<VectorType>()) - if (RHSVecType->getVectorKind() == VectorType::AltiVecBool) + if (RHSVecType->getVectorKind() == VectorKind::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); } return checkVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) + return checkSizelessVectorShift(*this, LHS, RHS, Loc, IsCompAssign); + // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 @@ -11150,7 +12444,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, isScopedEnumerationType(RHSType)) { return InvalidOperands(Loc, LHS, RHS); } - // Sanity-check shift operands DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType); // "The type of the result is that of the promoted left operand." @@ -11428,6 +12721,11 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, S.inTemplateInstantiation()) return; + // WebAssembly Tables cannot be compared, therefore shouldn't emit + // Tautological diagnostics. + if (LHSType->isWebAssemblyTableType() || RHSType->isWebAssemblyTableType()) + return; + // Comparisons between two array types are ill-formed for operator<=>, so // we shouldn't emit any additional warnings about it. if (Opc == BO_Cmp && LHSType->isArrayType() && RHSType->isArrayType()) @@ -11669,7 +12967,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); @@ -11686,7 +12984,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); @@ -11724,8 +13022,8 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, return S.InvalidOperands(Loc, LHS, RHS); // Check for comparisons of floating point operands using != and ==. - if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc)) - S.CheckFloatComparison(Loc, LHS.get(), RHS.get()); + if (Type->hasFloatingRepresentation()) + S.CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc); // The result of comparisons is 'bool' in C++, 'int' in C. return S.Context.getLogicalOperationType(); @@ -11801,6 +13099,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, RHS.get()->getType()->isVectorType()) return CheckVectorCompareOperands(LHS, RHS, Loc, Opc); + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) + return CheckSizelessVectorCompareOperands(LHS, RHS, Loc, Opc); + diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); @@ -11810,6 +13112,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, (RHSType->isArithmeticType() || RHSType->isEnumeralType())) return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc); + if ((LHSType->isPointerType() && + LHSType->getPointeeType().isWebAssemblyReferenceType()) || + (RHSType->isPointerType() && + RHSType->getPointeeType().isWebAssemblyReferenceType())) + return InvalidOperands(Loc, LHS, RHS); + const Expr::NullPointerConstantKind LHSNullKind = LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); const Expr::NullPointerConstantKind RHSNullKind = @@ -11826,7 +13134,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); @@ -11971,34 +13279,55 @@ 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. + // C23 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 the + // former is a null pointer. + 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)) { + // C23 6.5.9p6: + // Otherwise, at least one operand is a pointer. If one is a pointer and + // the other is a null pointer constant or has type nullptr_t, they + // compare equal + 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()))) { @@ -12191,7 +13520,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return computeResultTy(); } - if (getLangOpts().OpenCLVersion >= 200 || getLangOpts().OpenCLCPlusPlus) { + if (getLangOpts().getOpenCLCompatibleVersion() >= 200) { if (LHSType->isClkEventT() && RHSType->isClkEventT()) { return computeResultTy(); } @@ -12224,35 +13553,54 @@ QualType Sema::GetSignedVectorType(QualType V) { unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); if (isa<ExtVectorType>(VTy)) { + if (VTy->isExtVectorBoolType()) + return Context.getExtVectorType(Context.BoolTy, VTy->getNumElements()); if (TypeSize == Context.getTypeSize(Context.CharTy)) return Context.getExtVectorType(Context.CharTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.ShortTy)) + if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.IntTy)) + if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.LongTy)) + if (TypeSize == Context.getTypeSize(Context.Int128Ty)) + return Context.getExtVectorType(Context.Int128Ty, VTy->getNumElements()); + if (TypeSize == Context.getTypeSize(Context.LongTy)) return Context.getExtVectorType(Context.LongTy, VTy->getNumElements()); assert(TypeSize == Context.getTypeSize(Context.LongLongTy) && "Unhandled vector element size in vector compare"); return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); } + if (TypeSize == Context.getTypeSize(Context.Int128Ty)) + return Context.getVectorType(Context.Int128Ty, VTy->getNumElements(), + VectorKind::Generic); if (TypeSize == Context.getTypeSize(Context.LongLongTy)) return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(), - VectorType::GenericVector); - else if (TypeSize == Context.getTypeSize(Context.LongTy)) + VectorKind::Generic); + if (TypeSize == Context.getTypeSize(Context.LongTy)) return Context.getVectorType(Context.LongTy, VTy->getNumElements(), - VectorType::GenericVector); - else if (TypeSize == Context.getTypeSize(Context.IntTy)) + VectorKind::Generic); + if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getVectorType(Context.IntTy, VTy->getNumElements(), - VectorType::GenericVector); - else if (TypeSize == Context.getTypeSize(Context.ShortTy)) + VectorKind::Generic); + if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getVectorType(Context.ShortTy, VTy->getNumElements(), - VectorType::GenericVector); + VectorKind::Generic); assert(TypeSize == Context.getTypeSize(Context.CharTy) && "Unhandled vector element size in vector compare"); return Context.getVectorType(Context.CharTy, VTy->getNumElements(), - VectorType::GenericVector); + VectorKind::Generic); +} + +QualType Sema::GetSignedSizelessVectorType(QualType V) { + const BuiltinType *VTy = V->castAs<BuiltinType>(); + assert(VTy->isSizelessBuiltinType() && "expected sizeless type"); + + const QualType ETy = V->getSveEltType(Context); + const auto TypeSize = Context.getTypeSize(ETy); + + const QualType IntTy = Context.getIntTypeForBitwidth(TypeSize, true); + const llvm::ElementCount VecSize = Context.getBuiltinVectorTypeInfo(VTy).EC; + return Context.getScalableVectorType(IntTy, VecSize.getKnownMinValue()); } /// CheckVectorCompareOperands - vector comparisons are a clang extension that @@ -12269,9 +13617,12 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. - QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/getLangOpts().ZVector); + QualType vType = + CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ true, + /*ReportInvalid*/ true); if (vType.isNull()) return vType; @@ -12288,7 +13639,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, // If AltiVec, the comparison results in a numeric type, i.e. // bool for C++, int for C if (vType->castAs<VectorType>()->getVectorKind() == - VectorType::AltiVecVector) + VectorKind::AltiVecVector) return Context.getLogicalOperationType(); else Diag(Loc, diag::warn_deprecated_altivec_src_compat); @@ -12308,16 +13659,56 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); // Check for comparisons of floating point operands using != and ==. - if (BinaryOperator::isEqualityOp(Opc) && - LHSType->hasFloatingRepresentation()) { + if (LHSType->hasFloatingRepresentation()) { assert(RHS.get()->getType()->hasFloatingRepresentation()); - CheckFloatComparison(Loc, LHS.get(), RHS.get()); + CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc); } // Return a signed type for the vector. return GetSignedVectorType(vType); } +QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc) { + if (Opc == BO_Cmp) { + Diag(Loc, diag::err_three_way_vector_comparison); + return QualType(); + } + + // Check to make sure we're operating on vectors of the same type and width, + // Allowing one side to be a scalar of element type. + QualType vType = CheckSizelessVectorOperands( + LHS, RHS, Loc, /*isCompAssign*/ false, ACK_Comparison); + + if (vType.isNull()) + return vType; + + QualType LHSType = LHS.get()->getType(); + + // For non-floating point types, check for self-comparisons of the form + // x == x, x != x, x < x, etc. These always evaluate to a constant, and + // often indicate logic errors in the program. + diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); + + // Check for comparisons of floating point operands using != and ==. + if (LHSType->hasFloatingRepresentation()) { + assert(RHS.get()->getType()->hasFloatingRepresentation()); + CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc); + } + + const BuiltinType *LHSBuiltinTy = LHSType->getAs<BuiltinType>(); + const BuiltinType *RHSBuiltinTy = RHS.get()->getType()->getAs<BuiltinType>(); + + if (LHSBuiltinTy && RHSBuiltinTy && LHSBuiltinTy->isSVEBool() && + RHSBuiltinTy->isSVEBool()) + return LHSType; + + // Return a signed type for the vector. + return GetSignedSizelessVectorType(vType); +} + static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, const ExprResult &XorRHS, const SourceLocation Loc) { @@ -12392,14 +13783,13 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, StringRef RHSStrRef = RHSStr; // Do not diagnose literals with digit separators, binary, hexadecimal, octal // literals. - if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") || - RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") || - LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") || - RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") || - (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) || - (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) || - LHSStrRef.find('\'') != StringRef::npos || - RHSStrRef.find('\'') != StringRef::npos) + if (LHSStrRef.starts_with("0b") || LHSStrRef.starts_with("0B") || + RHSStrRef.starts_with("0b") || RHSStrRef.starts_with("0B") || + LHSStrRef.starts_with("0x") || LHSStrRef.starts_with("0X") || + RHSStrRef.starts_with("0x") || RHSStrRef.starts_with("0X") || + (LHSStrRef.size() > 1 && LHSStrRef.starts_with("0")) || + (RHSStrRef.size() > 1 && RHSStrRef.starts_with("0")) || + LHSStrRef.contains('\'') || RHSStrRef.contains('\'')) return; bool SuggestXor = @@ -12446,12 +13836,15 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ false); if (vType.isNull()) return InvalidOperands(Loc, LHS, RHS); - if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && - !getLangOpts().OpenCLCPlusPlus && vType->hasFloatingRepresentation()) + if (getLangOpts().OpenCL && + getLangOpts().getOpenCLCompatibleVersion() < 120 && + vType->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the // usage of the logical operators && and || with vectors in C. This @@ -12485,7 +13878,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. @@ -12529,17 +13922,37 @@ 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); } +static bool isLegalBoolVectorBinaryOp(BinaryOperatorKind Opc) { + switch (Opc) { + default: + return false; + case BO_And: + case BO_AndAssign: + case BO_Or: + case BO_OrAssign: + case BO_Xor: + case BO_XorAssign: + return true; + } +} + inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { @@ -12548,13 +13961,35 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, bool IsCompAssign = Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign; + bool LegalBoolVecOperator = isLegalBoolVectorBinaryOp(Opc); + if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/true, - /*AllowBoolConversions*/getLangOpts().ZVector); + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ LegalBoolVecOperator, + /*ReportInvalid*/ true); + return InvalidOperands(Loc, LHS, RHS); + } + + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, + ACK_BitwiseOp); + return InvalidOperands(Loc, LHS, RHS); + } + + if (LHS.get()->getType()->isSveVLSBuiltinType() || + RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, + ACK_BitwiseOp); return InvalidOperands(Loc, LHS, RHS); } @@ -12586,7 +14021,8 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { // Check vector operands differently. - if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) return CheckVectorLogicalOperands(LHS, RHS, Loc); bool EnumConstantInBoolContext = false; @@ -12601,6 +14037,16 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (EnumConstantInBoolContext) Diag(Loc, diag::warn_enum_constant_in_bool_context); + // WebAssembly tables can't be used with logical operators. + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + const auto *LHSATy = dyn_cast<ArrayType>(LHSTy); + const auto *RHSATy = dyn_cast<ArrayType>(RHSTy); + if ((LHSATy && LHSATy->getElementType().isWebAssemblyReferenceType()) || + (RHSATy && RHSATy->getElementType().isWebAssemblyReferenceType())) { + return InvalidOperands(Loc, LHS, RHS); + } + // Diagnose cases where the user write a logical and/or but probably meant a // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. @@ -12616,18 +14062,17 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, Expr::EvalResult EVResult; if (RHS.get()->EvaluateAsInt(EVResult, Context)) { llvm::APSInt Result = EVResult.Val.getInt(); - if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() && + if ((getLangOpts().CPlusPlus && !RHS.get()->getType()->isBooleanType() && !RHS.get()->getExprLoc().isMacroID()) || (Result != 0 && Result != 1)) { Diag(Loc, diag::warn_logical_instead_of_bitwise) - << RHS.get()->getSourceRange() - << (Opc == BO_LAnd ? "&&" : "||"); + << RHS.get()->getSourceRange() << (Opc == BO_LAnd ? "&&" : "||"); // Suggest replacing the logical operator with the bitwise version Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator) << (Opc == BO_LAnd ? "&" : "|") - << FixItHint::CreateReplacement(SourceRange( - Loc, getLocForEndOfToken(Loc)), - Opc == BO_LAnd ? "&" : "|"); + << FixItHint::CreateReplacement( + SourceRange(Loc, getLocForEndOfToken(Loc)), + Opc == BO_LAnd ? "&" : "|"); if (Opc == BO_LAnd) // Suggest replacing "Foo() && kNonZero" with "Foo()" Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant) @@ -12913,7 +14358,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, // Then we append it to the list to check next in order. FieldTy = FieldTy.getCanonicalType(); if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) { - if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } } @@ -13121,7 +14566,8 @@ static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr, // C99 6.5.16.1 QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, - QualType CompoundType) { + QualType CompoundType, + BinaryOperatorKind Opc) { assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject)); // Verify that LHS is a modifiable lvalue, and emit error if not. @@ -13142,6 +14588,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, return QualType(); } + // WebAssembly tables can't be used on RHS of an assignment expression. + if (RHSType->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_art) << 0; + return QualType(); + } + AssignConvertType ConvTy; if (CompoundType.isNull()) { Expr *RHSCheck = RHS.get(); @@ -13233,27 +14685,24 @@ 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++2a [expr.ass]p6: - // [Compound-assignment] expressions are deprecated if E1 has - // volatile-qualified type - Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType; } } - // C99 6.5.16p3: The type of an assignment expression is the type of the - // left operand unless the left operand has qualified type, in which case - // it is the unqualified version of the type of the left operand. - // C99 6.5.16.1p2: In simple assignment, the value of the right operand - // is converted to the type of the assignment expression (above). + // C11 6.5.16p3: The type of an assignment expression is the type of the + // left operand would have after lvalue conversion. + // C11 6.3.2.1p2: ...this is called lvalue conversion. If the lvalue has + // qualified type, the value has the unqualified version of the type of the + // lvalue; additionally, if the lvalue has atomic type, the value has the + // non-atomic version of the type of the lvalue. // C++ 5.17p1: the type of the assignment expression is that of its left // operand. - return (getLangOpts().CPlusPlus - ? LHSType : LHSType.getUnqualifiedType()); + 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)) { @@ -13268,6 +14717,8 @@ static bool IgnoreCommaOperand(const Expr *E) { } } + if (const auto *CE = dyn_cast<CallExpr>(E)) + return CE->getCallReturnType(Context)->isVoidType(); return false; } @@ -13309,7 +14760,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); @@ -13340,7 +14791,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, if (LHS.isInvalid()) return QualType(); - S.DiagnoseUnusedExprResult(LHS.get()); + S.DiagnoseUnusedExprResult(LHS.get(), diag::warn_unused_comma_left_operand); if (!S.getLangOpts().CPlusPlus) { RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get()); @@ -13415,10 +14866,10 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else if (S.getLangOpts().ZVector && ResType->isVectorType() && (ResType->castAs<VectorType>()->getVectorKind() != - VectorType::AltiVecBool)) { + VectorKind::AltiVecBool)) { // The z vector extensions allow ++ and -- for non-bool vectors. - } else if(S.getLangOpts().OpenCL && ResType->isVectorType() && - ResType->castAs<VectorType>()->getElementType()->isIntegerType()) { + } else if (S.getLangOpts().OpenCL && ResType->isVectorType() && + ResType->castAs<VectorType>()->getElementType()->isIntegerType()) { // OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types. } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) @@ -13529,6 +14980,34 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc, S.Diag(Loc, diag::err_typecheck_address_of) << Type << E->getSourceRange(); } +bool Sema::CheckUseOfCXXMethodAsAddressOfOperand(SourceLocation OpLoc, + const Expr *Op, + const CXXMethodDecl *MD) { + const auto *DRE = cast<DeclRefExpr>(Op->IgnoreParens()); + + if (Op != DRE) + return Diag(OpLoc, diag::err_parens_pointer_member_function) + << Op->getSourceRange(); + + // Taking the address of a dtor is illegal per C++ [class.dtor]p2. + if (isa<CXXDestructorDecl>(MD)) + return Diag(OpLoc, diag::err_typecheck_addrof_dtor) + << DRE->getSourceRange(); + + if (DRE->getQualifier()) + return false; + + if (MD->getParent()->getName().empty()) + return Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << DRE->getSourceRange(); + + SmallString<32> Str; + StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str); + return Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << DRE->getSourceRange() + << FixItHint::CreateInsertion(DRE->getSourceRange().getBegin(), Qual); +} + /// CheckAddressOfOperand - The operand of & must be either a function /// designator or an lvalue designating an object. If it is an lvalue, the /// object cannot be declared with storage class register or be a bit field. @@ -13574,7 +15053,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { if (OrigOp.get()->isTypeDependent()) return Context.DependentTy; - assert(!OrigOp.get()->getType()->isPlaceholderType()); + assert(!OrigOp.get()->hasPlaceholderType()); // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp.get()->IgnoreParens(); @@ -13638,28 +15117,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { DeclRefExpr *DRE = cast<DeclRefExpr>(op); CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl()); - // The id-expression was parenthesized. - if (OrigOp.get() != DRE) { - Diag(OpLoc, diag::err_parens_pointer_member_function) - << OrigOp.get()->getSourceRange(); - - // The method was named without a qualifier. - } else if (!DRE->getQualifier()) { - if (MD->getParent()->getName().empty()) - Diag(OpLoc, diag::err_unqualified_pointer_member_function) - << op->getSourceRange(); - else { - SmallString<32> Str; - StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str); - Diag(OpLoc, diag::err_unqualified_pointer_member_function) - << op->getSourceRange() - << FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual); - } - } - - // Taking the address of a dtor is illegal per C++ [class.dtor]p2. - if (isa<CXXDestructorDecl>(MD)) - Diag(OpLoc, diag::err_typecheck_addrof_dtor) << op->getSourceRange(); + CheckUseOfCXXMethodAsAddressOfOperand(OpLoc, OrigOp.get(), MD); QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); @@ -13679,7 +15137,11 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { << op->getType() << op->getSourceRange(); return QualType(); } + } else if (const auto *DRE = dyn_cast<DeclRefExpr>(op)) { + if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl())) + CheckUseOfCXXMethodAsAddressOfOperand(OpLoc, OrigOp.get(), MD); } + } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1 // The operand cannot be a bit-field AddressOfError = AO_Bit_Field; @@ -13729,8 +15191,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { return MPTy; } } - } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) && - !isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl)) + } else if (!isa<FunctionDecl, NonTypeTemplateParmDecl, BindingDecl, + MSGuidDecl, UnnamedGlobalConstantDecl>(dcl)) llvm_unreachable("Unknown/unexpected decl type"); } @@ -13750,6 +15212,21 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); + // Cannot take the address of WebAssembly references or tables. + if (Context.getTargetInfo().getTriple().isWasm()) { + QualType OpTy = op->getType(); + if (OpTy.isWebAssemblyReferenceType()) { + Diag(OpLoc, diag::err_wasm_ca_reference) + << 1 << OrigOp.get()->getSourceRange(); + return QualType(); + } + if (OpTy->isWebAssemblyTableType()) { + Diag(OpLoc, diag::err_wasm_table_pr) + << 1 << OrigOp.get()->getSourceRange(); + return QualType(); + } + } + CheckAddressOfPackedMember(op); return Context.getPointerType(op->getType()); @@ -13769,13 +15246,13 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) { if (!FD->hasAttr<NonNullAttr>() && !Param->hasAttr<NonNullAttr>()) return; if (FunctionScopeInfo *FD = S.getCurFunction()) - if (!FD->ModifiedNonNullParams.count(Param)) - FD->ModifiedNonNullParams.insert(Param); + FD->ModifiedNonNullParams.insert(Param); } /// 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; @@ -13812,18 +15289,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::err_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; @@ -13896,6 +15373,40 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( return Opc; } +const FieldDecl * +Sema::getSelfAssignmentClassMemberCandidate(const ValueDecl *SelfAssigned) { + // Explore the case for adding 'this->' to the LHS of a self assignment, very + // common for setters. + // struct A { + // int X; + // -void setX(int X) { X = X; } + // +void setX(int X) { this->X = X; } + // }; + + // Only consider parameters for self assignment fixes. + if (!isa<ParmVarDecl>(SelfAssigned)) + return nullptr; + const auto *Method = + dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl(true)); + if (!Method) + return nullptr; + + const CXXRecordDecl *Parent = Method->getParent(); + // In theory this is fixable if the lambda explicitly captures this, but + // that's added complexity that's rarely going to be used. + if (Parent->isLambda()) + return nullptr; + + // FIXME: Use an actual Lookup operation instead of just traversing fields + // in order to get base class fields. + auto Field = + llvm::find_if(Parent->fields(), + [Name(SelfAssigned->getDeclName())](const FieldDecl *F) { + return F->getDeclName() == Name; + }); + return (Field != Parent->field_end()) ? *Field : nullptr; +} + /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. /// This warning suppressed in the event of macro expansions. static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, @@ -13926,10 +15437,16 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, if (RefTy->getPointeeType().isVolatileQualified()) return; - S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin - : diag::warn_self_assignment_overloaded) - << LHSDeclRef->getType() << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); + auto Diag = S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin + : diag::warn_self_assignment_overloaded) + << LHSDeclRef->getType() << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); + if (const FieldDecl *SelfAssignField = + S.getSelfAssignmentClassMemberCandidate(RHSDecl)) + Diag << 1 << SelfAssignField + << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->"); + else + Diag << 0; } /// Check if a bitwise-& is performed on an Objective-C pointer. This @@ -13966,7 +15483,7 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) { Selector S = ME->getSelector(); StringRef SelArg0 = S.getNameForSlot(0); - if (SelArg0.startswith("performSelector")) + if (SelArg0.starts_with("performSelector")) Diag = diag::warn_objc_pointer_masking_performSelector; } @@ -14060,7 +15577,7 @@ static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, // the vectors shouldn't be treated as storage-only types. See the // discussion here: https://reviews.llvm.org/rG825235c140e7 if (const VectorType *VT = Ty->getAs<VectorType>()) { - if (VT->getVectorKind() == VectorType::NeonVector) + if (VT->getVectorKind() == VectorKind::Neon) return false; return VT->getElementType().getCanonicalType() == Ctx.HalfTy; } @@ -14132,9 +15649,12 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } } + checkTypeSupport(LHSExpr->getType(), OpLoc, /*ValueDecl*/ nullptr); + checkTypeSupport(RHSExpr->getType(), OpLoc, /*ValueDecl*/ nullptr); + switch (Opc) { case BO_Assign: - ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType(), Opc); if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = LHS.get()->getValueKind(); @@ -14214,7 +15734,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); @@ -14231,42 +15751,48 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, Opc == BO_DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) - ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); + ResultTy = + CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); break; case BO_RemAssign: CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) - ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); + ResultTy = + CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); 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); + ResultTy = + CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); 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); + ResultTy = + CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); break; case BO_ShlAssign: case BO_ShrAssign: CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) - ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); + ResultTy = + CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); break; 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; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) - ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); + ResultTy = + CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc); break; case BO_Comma: ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc); @@ -14403,38 +15929,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); } } @@ -14446,11 +15955,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); } } @@ -14583,13 +16090,22 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, Expr *LHS, Expr *RHS) { switch (Opc) { case BO_Assign: + // In the non-overloaded case, we warn about self-assignment (x = x) for + // both simple assignment and certain compound assignments where algebra + // tells us the operation yields a constant result. When the operator is + // overloaded, we can't do the latter because we don't want to assume that + // those algebraic identities still apply; for example, a path-building + // library might use operator/= to append paths. But it's still reasonable + // to assume that simple assignment is just moving/copying values around + // and so self-assignment is likely a bug. + DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); + [[fallthrough]]; case BO_DivAssign: case BO_RemAssign: case BO_SubAssign: case BO_AndAssign: case BO_OrAssign: case BO_XorAssign: - DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); CheckIdentityFieldAssignment(LHS, RHS, OpLoc, S); break; default: @@ -14655,7 +16171,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, pty->getKind() == BuiltinType::Overload)) { auto *OE = dyn_cast<OverloadExpr>(LHSExpr); if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() && - std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) { + llvm::any_of(OE->decls(), [](NamedDecl *ND) { return isa<FunctionTemplateDecl>(ND); })) { Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc() @@ -14756,15 +16272,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; @@ -14786,6 +16302,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } } + if (getLangOpts().HLSL && OpLoc.isValid()) { + if (Opc == UO_AddrOf) + return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0); + if (Opc == UO_Deref) + return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 1); + } + switch (Opc) { case UO_PreInc: case UO_PreDec: @@ -14807,7 +16330,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: @@ -14834,7 +16358,9 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // The z vector extensions don't allow + or - with bool vectors. (!Context.getLangOpts().ZVector || resultType->castAs<VectorType>()->getVectorKind() != - VectorType::AltiVecBool)) + VectorKind::AltiVecBool)) + break; + else if (resultType->isSveVLSBuiltinType()) // SVE vectors allow + and - break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 Opc == UO_Plus && @@ -14883,6 +16409,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = Context.FloatTy; } + // WebAsembly tables can't be used in unary expressions. + if (resultType->isPointerType() && + resultType->getPointeeType().isWebAssemblyReferenceType()) { + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); + } + if (resultType->isDependentType()) break; if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) { @@ -14902,8 +16435,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && - Context.getLangOpts().OpenCLVersion < 120 && - !Context.getLangOpts().OpenCLCPlusPlus) { + Context.getLangOpts().getOpenCLCompatibleVersion() < 120) { // OpenCL v1.1 6.3.h: The logical operator not (!) does not // operate on vector float types. QualType T = resultType->castAs<ExtVectorType>()->getElementType(); @@ -14916,7 +16448,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, break; } else if (Context.getLangOpts().CPlusPlus && resultType->isVectorType()) { const VectorType *VTy = resultType->castAs<VectorType>(); - if (VTy->getVectorKind() != VectorType::GenericVector) + if (VTy->getVectorKind() != VectorKind::Generic) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); @@ -15000,7 +16532,7 @@ bool Sema::isQualifiedMemberAccess(Expr *E) { if (isa<FieldDecl>(VD) || isa<IndirectFieldDecl>(VD)) return true; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(VD)) - return Method->isInstance(); + return Method->isImplicitObjectMemberFunction(); return false; } @@ -15011,7 +16543,7 @@ bool Sema::isQualifiedMemberAccess(Expr *E) { for (NamedDecl *D : ULE->decls()) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - if (Method->isInstance()) + if (Method->isImplicitObjectMemberFunction()) return true; } else { // Overload set does not contain methods. @@ -15026,7 +16558,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()) { @@ -15065,13 +16598,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". @@ -15079,12 +16613,19 @@ 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() { PushExpressionEvaluationContext(ExprEvalContexts.back().Context); + // Make sure we diagnose jumping into a statement expression. + setFunctionHasBranchProtectedScope(); } void Sema::ActOnStmtExprError() { @@ -15261,12 +16802,11 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, LangOpts.CPlusPlus11? diag::ext_offsetof_non_standardlayout_type : diag::ext_offsetof_non_pod_type; - if (!IsSafe && !DidWarnAboutNonPOD && - DiagRuntimeBehavior(BuiltinLoc, nullptr, - PDiag(DiagID) - << SourceRange(Components[0].LocStart, OC.LocEnd) - << CurrentType)) + if (!IsSafe && !DidWarnAboutNonPOD && !isUnevaluatedContext()) { + Diag(BuiltinLoc, DiagID) + << SourceRange(Components[0].LocStart, OC.LocEnd) << CurrentType; DidWarnAboutNonPOD = true; + } } // Look for the field. @@ -15279,10 +16819,15 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, MemberDecl = IndirectMemberDecl->getAnonField(); } - if (!MemberDecl) - return ExprError(Diag(BuiltinLoc, diag::err_no_member) - << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, - OC.LocEnd)); + if (!MemberDecl) { + // Lookup could be ambiguous when looking up a placeholder variable + // __builtin_offsetof(S, _). + // In that case we would already have emitted a diagnostic + if (!R.isAmbiguous()) + Diag(BuiltinLoc, diag::err_no_member) + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd); + return ExprError(); + } // C99 7.17p3: // (If the specified member is a bit-field, the behavior is undefined.) @@ -15427,7 +16972,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, assert(ParamInfo.getContext() == DeclaratorContext::BlockLiteral); BlockScopeInfo *CurBlock = getCurBlock(); - TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope); + TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo); QualType T = Sig->getType(); // FIXME: We should allow unexpanded parameter packs here, but that would, @@ -15437,7 +16982,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); } @@ -15497,8 +17042,8 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, if (Param->getIdentifier() == nullptr && !Param->isImplicit() && !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) { // Diagnose this as an extension in C17 and earlier. - if (!getLangOpts().C2x) - Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x); + if (!getLangOpts().C23) + Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c23); } Params.push_back(Param); } @@ -15524,7 +17069,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. @@ -15533,6 +17078,9 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, PushOnScopeChains(AI, CurBlock->TheScope); } + + if (AI->isInvalidDecl()) + CurBlock->TheDecl->setInvalidDecl(); } } @@ -15587,10 +17135,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; @@ -15608,7 +17156,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()); @@ -15643,8 +17191,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 = @@ -15732,6 +17281,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (getCurFunction()) getCurFunction()->addBlock(BD); + if (BD->isInvalidDecl()) + return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(), + {Result}, Result->getType()); return Result; } @@ -15758,7 +17310,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, } // NVPTX does not support va_arg expression. - if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice && Context.getTargetInfo().getTriple().isNVPTX()) targetDiag(E->getBeginLoc(), diag::err_va_arg_in_device); @@ -15837,20 +17389,23 @@ 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: + // and C23 7.16.1.1p2 says, in part: // If type is not compatible with the type of the actual next argument // (as promoted according to the default argument promotions), the // behavior is undefined, except for the following cases: // - both types are pointers to qualified or unqualified versions of // compatible types; - // - one type is a signed integer type, the other type is the - // corresponding unsigned integer type, and the value is - // representable in both types; + // - one type is compatible with a signed integer type, the other + // type is compatible with the corresponding unsigned integer type, + // and the value is representable in both types; // - one type is pointer to qualified or unqualified void and the - // other is a pointer to a qualified or unqualified character type. + // other is a pointer to a qualified or unqualified character type; + // - or, the type of the next argument is nullptr_t and type is a + // pointer type that has the same representation and alignment + // requirements as a pointer to a character type. // Given that type compatibility is the primary requirement (ignoring // qualifications), you would think we could call typesAreCompatible() // directly to test this. However, in C++, that checks for *same type*, @@ -15868,7 +17423,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // promoted type and the underlying type are the same except for // signedness. Ask the AST for the correctly corresponding type and see // if that's compatible. - if (!PromoteType.isNull() && + if (!PromoteType.isNull() && !UnderlyingType->isBooleanType() && PromoteType->isUnsignedIntegerType() != UnderlyingType->isUnsignedIntegerType()) { UnderlyingType = @@ -15898,7 +17453,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()) @@ -15912,18 +17467,112 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return new (Context) GNUNullExpr(Ty, TokenLoc); } -ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, +static CXXRecordDecl *LookupStdSourceLocationImpl(Sema &S, SourceLocation Loc) { + CXXRecordDecl *ImplDecl = nullptr; + + // Fetch the std::source_location::__impl decl. + if (NamespaceDecl *Std = S.getStdNamespace()) { + LookupResult ResultSL(S, &S.PP.getIdentifierTable().get("source_location"), + Loc, Sema::LookupOrdinaryName); + if (S.LookupQualifiedName(ResultSL, Std)) { + if (auto *SLDecl = ResultSL.getAsSingle<RecordDecl>()) { + LookupResult ResultImpl(S, &S.PP.getIdentifierTable().get("__impl"), + Loc, Sema::LookupOrdinaryName); + if ((SLDecl->isCompleteDefinition() || SLDecl->isBeingDefined()) && + S.LookupQualifiedName(ResultImpl, SLDecl)) { + ImplDecl = ResultImpl.getAsSingle<CXXRecordDecl>(); + } + } + } + } + + if (!ImplDecl || !ImplDecl->isCompleteDefinition()) { + S.Diag(Loc, diag::err_std_source_location_impl_not_found); + return nullptr; + } + + // Verify that __impl is a trivial struct type, with no base classes, and with + // only the four expected fields. + if (ImplDecl->isUnion() || !ImplDecl->isStandardLayout() || + ImplDecl->getNumBases() != 0) { + S.Diag(Loc, diag::err_std_source_location_impl_malformed); + return nullptr; + } + + unsigned Count = 0; + for (FieldDecl *F : ImplDecl->fields()) { + StringRef Name = F->getName(); + + if (Name == "_M_file_name") { + if (F->getType() != + S.Context.getPointerType(S.Context.CharTy.withConst())) + break; + Count++; + } else if (Name == "_M_function_name") { + if (F->getType() != + S.Context.getPointerType(S.Context.CharTy.withConst())) + break; + Count++; + } else if (Name == "_M_line") { + if (!F->getType()->isIntegerType()) + break; + Count++; + } else if (Name == "_M_column") { + if (!F->getType()->isIntegerType()) + break; + Count++; + } else { + Count = 100; // invalid + break; + } + } + if (Count != 4) { + S.Diag(Loc, diag::err_std_source_location_impl_malformed); + return nullptr; + } + + return ImplDecl; +} + +ExprResult Sema::ActOnSourceLocExpr(SourceLocIdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc) { - return BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, CurContext); + QualType ResultTy; + switch (Kind) { + case SourceLocIdentKind::File: + case SourceLocIdentKind::FileName: + case SourceLocIdentKind::Function: + case SourceLocIdentKind::FuncSig: { + QualType ArrTy = Context.getStringLiteralArrayType(Context.CharTy, 0); + ResultTy = + Context.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType()); + break; + } + case SourceLocIdentKind::Line: + case SourceLocIdentKind::Column: + ResultTy = Context.UnsignedIntTy; + break; + case SourceLocIdentKind::SourceLocStruct: + if (!StdSourceLocationImplDecl) { + StdSourceLocationImplDecl = + LookupStdSourceLocationImpl(*this, BuiltinLoc); + if (!StdSourceLocationImplDecl) + return ExprError(); + } + ResultTy = Context.getPointerType( + Context.getRecordType(StdSourceLocationImplDecl).withConst()); + break; + } + + return BuildSourceLocExpr(Kind, ResultTy, BuiltinLoc, RPLoc, CurContext); } -ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, +ExprResult Sema::BuildSourceLocExpr(SourceLocIdentKind Kind, QualType ResultTy, SourceLocation BuiltinLoc, SourceLocation RPLoc, DeclContext *ParentContext) { return new (Context) - SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext); + SourceLocExpr(Context, Kind, ResultTy, BuiltinLoc, RPLoc, ParentContext); } bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp, @@ -15948,7 +17597,7 @@ bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp, if (!PT->isObjCIdType() && !(ID && ID->getIdentifier()->isStr("NSString"))) return false; - if (!SL->isAscii()) + if (!SL->isOrdinary()) return false; if (Diagnose) { @@ -16043,6 +17692,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; @@ -16229,10 +17884,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, } PartialDiagnostic FDiag = PDiag(DiagKind); + AssignmentAction ActionForDiag = Action; if (Action == AA_Passing_CFAudited) - FDiag << FirstType << SecondType << AA_Passing << SrcExpr->getSourceRange(); - else - FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange(); + ActionForDiag = AA_Passing; + + FDiag << FirstType << SecondType << ActionForDiag + << SrcExpr->getSourceRange(); if (DiagKind == diag::ext_typecheck_convert_incompatible_pointer_sign || DiagKind == diag::err_typecheck_convert_incompatible_pointer_sign) { @@ -16524,12 +18181,41 @@ ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { return TransformToPE(*this).TransformExpr(E); } +TypeSourceInfo *Sema::TransformToPotentiallyEvaluated(TypeSourceInfo *TInfo) { + assert(isUnevaluatedContext() && + "Should only transform unevaluated expressions"); + ExprEvalContexts.back().Context = + ExprEvalContexts[ExprEvalContexts.size() - 2].Context; + if (isUnevaluatedContext()) + return TInfo; + return TransformToPE(*this).TransformType(TInfo); +} + void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, LambdaContextDecl, ExprContext); + + // Discarded statements and immediate contexts nested in other + // discarded statements or immediate context are themselves + // a discarded statement or an immediate context, respectively. + ExprEvalContexts.back().InDiscardedStatement = + ExprEvalContexts[ExprEvalContexts.size() - 2] + .isDiscardedStatementContext(); + + // C++23 [expr.const]/p15 + // An expression or conversion is in an immediate function context if [...] + // it is a subexpression of a manifestly constant-evaluated expression or + // conversion. + const auto &Prev = ExprEvalContexts[ExprEvalContexts.size() - 2]; + ExprEvalContexts.back().InImmediateFunctionContext = + Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated(); + + ExprEvalContexts.back().InImmediateEscalatingFunctionContext = + Prev.InImmediateEscalatingFunctionContext; + Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); @@ -16602,15 +18288,37 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) { if (BO->getOpcode() == BO_Assign) { auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs; - LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()), - LHSs.end()); + llvm::erase(LHSs, BO->getLHS()); } } } +void Sema::MarkExpressionAsImmediateEscalating(Expr *E) { + assert(getLangOpts().CPlusPlus20 && + ExprEvalContexts.back().InImmediateEscalatingFunctionContext && + "Cannot mark an immediate escalating expression outside of an " + "immediate escalating context"); + if (auto *Call = dyn_cast<CallExpr>(E->IgnoreImplicit()); + Call && Call->getCallee()) { + if (auto *DeclRef = + dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) + DeclRef->setIsImmediateEscalating(true); + } else if (auto *Ctr = dyn_cast<CXXConstructExpr>(E->IgnoreImplicit())) { + Ctr->setIsImmediateEscalating(true); + } else if (auto *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreImplicit())) { + DeclRef->setIsImmediateEscalating(true); + } else { + assert(false && "expected an immediately escalating expression"); + } + if (FunctionScopeInfo *FI = getCurFunction()) + FI->FoundImmediateEscalatingExpression = true; +} + ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { - if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || - RebuildingImmediateInvocation) + if (isUnevaluatedContext() || !E.isUsable() || !Decl || + !Decl->isImmediateFunction() || isAlwaysConstantEvaluatedContext() || + isCheckingDefaultArgumentOrInitializer() || + RebuildingImmediateInvocation || isImmediateFunctionContext()) return E; /// Opportunistically remove the callee from ReferencesToConsteval if we can. @@ -16622,14 +18330,63 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef); - E = MaybeCreateExprWithCleanups(E); + // C++23 [expr.const]/p16 + // An expression or conversion is immediate-escalating if it is not initially + // in an immediate function context and it is [...] an immediate invocation + // that is not a constant expression and is not a subexpression of an + // immediate invocation. + APValue Cached; + auto CheckConstantExpressionAndKeepResult = [&]() { + llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + Expr::EvalResult Eval; + Eval.Diag = &Notes; + bool Res = E.get()->EvaluateAsConstantExpr( + Eval, getASTContext(), ConstantExprKind::ImmediateInvocation); + if (Res && Notes.empty()) { + Cached = std::move(Eval.Val); + return true; + } + return false; + }; + + if (!E.get()->isValueDependent() && + ExprEvalContexts.back().InImmediateEscalatingFunctionContext && + !CheckConstantExpressionAndKeepResult()) { + MarkExpressionAsImmediateEscalating(E.get()); + return E; + } + + if (Cleanup.exprNeedsCleanups()) { + // Since an immediate invocation is a full expression itself - it requires + // an additional ExprWithCleanups node, but it can participate to a bigger + // full expression which actually requires cleanups to be run after so + // create ExprWithCleanups without using MaybeCreateExprWithCleanups as it + // may discard cleanups for outer expression too early. + + // Note that ExprWithCleanups created here must always have empty cleanup + // objects: + // - compound literals do not create cleanup objects in C++ and immediate + // invocations are C++-only. + // - blocks are not allowed inside constant expressions and compiler will + // issue an error if they appear there. + // + // Hence, in correct code any cleanup objects created inside current + // evaluation context must be outside the immediate invocation. + E = ExprWithCleanups::Create(getASTContext(), E.get(), + Cleanup.cleanupsHaveSideEffects(), {}); + } ConstantExpr *Res = ConstantExpr::Create( getASTContext(), E.get(), ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(), getASTContext()), /*IsImmediateInvocation*/ true); - ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); + if (Cached.hasValue()) + Res->MoveIntoResult(Cached, getASTContext()); + /// Value-dependent constant expressions should not be immediately + /// evaluated until they are instantiated. + if (!Res->isValueDependent()) + ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); return Res; } @@ -16642,18 +18399,32 @@ static void EvaluateAndDiagnoseImmediateInvocation( bool Result = CE->EvaluateAsConstantExpr( Eval, SemaRef.getASTContext(), ConstantExprKind::ImmediateInvocation); if (!Result || !Notes.empty()) { + SemaRef.FailedImmediateInvocations.insert(CE); Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit(); if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr)) - InnerExpr = FunctionalCast->getSubExpr(); + InnerExpr = FunctionalCast->getSubExpr()->IgnoreImplicit(); FunctionDecl *FD = nullptr; if (auto *Call = dyn_cast<CallExpr>(InnerExpr)) FD = cast<FunctionDecl>(Call->getCalleeDecl()); else if (auto *Call = dyn_cast<CXXConstructExpr>(InnerExpr)) FD = Call->getConstructor(); - else - llvm_unreachable("unhandled decl kind"); - assert(FD->isConsteval()); - SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD; + else if (auto *Cast = dyn_cast<CastExpr>(InnerExpr)) + FD = dyn_cast_or_null<FunctionDecl>(Cast->getConversionFunction()); + + assert(FD && FD->isImmediateFunction() && + "could not find an immediate function in this expression"); + if (FD->isInvalidDecl()) + return; + SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) + << FD << FD->isConsteval(); + 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); + } + if (!FD->isConsteval()) + SemaRef.DiagnoseImmediateEscalatingReason(FD); for (auto &Note : Notes) SemaRef.Diag(Note.first, Note.second); return; @@ -16680,10 +18451,16 @@ static void RemoveNestedImmediateInvocation( [E](Sema::ImmediateInvocationCandidate Elem) { return Elem.getPointer() == E; }); - assert(It != IISet.rend() && - "ConstantExpr marked IsImmediateInvocation should " - "be present"); - It->setInt(1); // Mark as deleted + // It is possible that some subexpression of the current immediate + // invocation was handled from another expression evaluation context. Do + // not handle the current immediate invocation if some of its + // subexpressions failed before. + if (It == IISet.rend()) { + if (SemaRef.FailedImmediateInvocations.contains(E)) + CurrentII->setInt(1); + } else { + It->setInt(1); // Mark as deleted + } } ExprResult TransformConstantExpr(ConstantExpr *E) { if (!E->isImmediateInvocation()) @@ -16697,7 +18474,10 @@ static void RemoveNestedImmediateInvocation( DRSet.erase(cast<DeclRefExpr>(E->getCallee()->IgnoreImplicit())); return Base::TransformCXXOperatorCallExpr(E); } - /// Base::TransformInitializer skip ConstantExpr so we need to visit them + /// Base::TransformUserDefinedLiteral doesn't preserve the + /// UserDefinedLiteral node. + ExprResult TransformUserDefinedLiteral(UserDefinedLiteral *E) { return E; } + /// Base::TransformInitializer skips ConstantExpr so we need to visit them /// here. ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) { if (!Init) @@ -16713,6 +18493,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() { @@ -16734,9 +18519,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 @@ -16747,14 +18536,17 @@ HandleImmediateInvocations(Sema &SemaRef, SemaRef.RebuildingImmediateInvocation) return; - /// When we have more then 1 ImmediateInvocationCandidates we need to check - /// for nested ImmediateInvocationCandidates. when we have only 1 we only - /// need to remove ReferenceToConsteval in the immediate invocation. - if (Rec.ImmediateInvocationCandidates.size() > 1) { + /// When we have more than 1 ImmediateInvocationCandidates or previously + /// failed immediate invocations, we need to check for nested + /// ImmediateInvocationCandidates in order to avoid duplicate diagnostics. + /// Otherwise we only need to remove ReferenceToConsteval in the immediate + /// invocation. + if (Rec.ImmediateInvocationCandidates.size() > 1 || + !SemaRef.FailedImmediateInvocations.empty()) { /// 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 @@ -16780,11 +18572,49 @@ HandleImmediateInvocations(Sema &SemaRef, for (auto CE : Rec.ImmediateInvocationCandidates) if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); - for (auto DR : Rec.ReferenceToConsteval) { + for (auto *DR : Rec.ReferenceToConsteval) { + // If the expression is immediate escalating, it is not an error; + // The outer context itself becomes immediate and further errors, + // if any, will be handled by DiagnoseImmediateEscalatingReason. + if (DR->isImmediateEscalating()) + continue; auto *FD = cast<FunctionDecl>(DR->getDecl()); - SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) - << FD; - SemaRef.Diag(FD->getLocation(), diag::note_declared_at); + const NamedDecl *ND = FD; + if (const auto *MD = dyn_cast<CXXMethodDecl>(ND); + MD && (MD->isLambdaStaticInvoker() || isLambdaCallOperator(MD))) + ND = MD->getParent(); + + // C++23 [expr.const]/p16 + // An expression or conversion is immediate-escalating if it is not + // initially in an immediate function context and it is [...] a + // potentially-evaluated id-expression that denotes an immediate function + // that is not a subexpression of an immediate invocation. + bool ImmediateEscalating = false; + bool IsPotentiallyEvaluated = + Rec.Context == + Sema::ExpressionEvaluationContext::PotentiallyEvaluated || + Rec.Context == + Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed; + if (SemaRef.inTemplateInstantiation() && IsPotentiallyEvaluated) + ImmediateEscalating = Rec.InImmediateEscalatingFunctionContext; + + if (!Rec.InImmediateEscalatingFunctionContext || + (SemaRef.inTemplateInstantiation() && !ImmediateEscalating)) { + SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) + << ND << isa<CXXRecordDecl>(ND) << FD->isConsteval(); + SemaRef.Diag(ND->getLocation(), diag::note_declared_at); + 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); + } + if (FD->isImmediateEscalating() && !FD->isConsteval()) + SemaRef.DiagnoseImmediateEscalatingReason(FD); + + } else { + SemaRef.MarkExpressionAsImmediateEscalating(DR); + } } } @@ -16881,6 +18711,8 @@ static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) { // An expression or conversion is potentially constant evaluated if it is switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::ImmediateFunctionContext: + // -- a manifestly constant-evaluated expression, case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: @@ -17003,6 +18835,7 @@ static OdrUseContext isOdrUseContext(Sema &SemaRef) { return OdrUseContext::None; case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::ImmediateFunctionContext: case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: Result = OdrUseContext::Used; break; @@ -17109,14 +18942,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (NeedDefinition && (Func->getTemplateSpecializationKind() != TSK_Undeclared || Func->getMemberSpecializationInfo())) - checkSpecializationVisibility(Loc, Func); + checkSpecializationReachability(Loc, Func); if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); - if (getLangOpts().SYCLIsDevice) - checkSYCLDeviceFunction(Loc, Func); - // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { runWithSufficientStackSpace(Loc, [&] { @@ -17218,7 +19048,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); } @@ -17226,6 +19056,24 @@ 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)) { + EnterExpressionEvaluationContext EvalContext( + *this, + Constructor->isImmediateFunction() + ? ExpressionEvaluationContext::ImmediateFunctionContext + : ExpressionEvaluationContext::PotentiallyEvaluated, + Constructor); + for (CXXCtorInitializer *Init : Constructor->inits()) { + if (Init->isInClassMemberInitializer()) + runWithSufficientStackSpace(Init->getSourceLocation(), [&]() { + 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, @@ -17239,6 +19087,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) ResolveExceptionSpec(Loc, FPT); + // A callee could be called by a host function then by a device function. + // If we only try recording once, we will miss recording the use on device + // side. Therefore keep trying until it is recorded. + if (LangOpts.OffloadImplicitHostDeviceTemplates && LangOpts.CUDAIsDevice && + !getASTContext().CUDAImplicitHostDeviceFunUsedByDevice.count(Func)) + CUDARecordImplicitHostDeviceFuncUsedByDevice(Func); + // If this is the first "real" use, act on that. if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) { // Keep track of used but undefined functions. @@ -17285,10 +19140,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)) && @@ -17299,14 +19157,13 @@ 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); - - if (SemaRef.LangOpts.CUDA && Var && Var->hasGlobalStorage()) { + 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); auto VarTarget = SemaRef.IdentifyCUDATarget(Var); auto UserTarget = SemaRef.IdentifyCUDATarget(FD); @@ -17316,7 +19173,7 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, // Diagnose ODR-use of host global variables in device functions. // Reference of device global variables in host functions is allowed // through shadow variables therefore it is not diagnosed. - if (SemaRef.LangOpts.CUDAIsDevice) { + if (SemaRef.LangOpts.CUDAIsDevice && !SemaRef.LangOpts.HIPStdPar) { SemaRef.targetDiag(Loc, diag::err_ref_bad_target) << /*host*/ 2 << /*variable*/ 1 << Var << UserTarget; SemaRef.targetDiag(Var->getLocation(), @@ -17325,9 +19182,9 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, : diag::note_cuda_host_var); } } else if (VarTarget == Sema::CVT_Device && + !Var->hasAttr<CUDASharedAttr>() && (UserTarget == Sema::CFT_Host || - UserTarget == Sema::CFT_HostDevice) && - !Var->hasExternalStorage()) { + UserTarget == Sema::CFT_HostDevice)) { // Record a CUDA/HIP device side variable if it is ODR-used // by host code. This is done conservatively, when the variable is // referenced in any of the following contexts: @@ -17338,22 +19195,24 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, // be visible in the device compilation for the compiler to be able to // emit template variables instantiated by host code only and to // externalize the static device side variable ODR-used by host code. - SemaRef.getASTContext().CUDADeviceVarODRUsedByHost.insert(Var); + if (!Var->hasExternalStorage()) + SemaRef.getASTContext().CUDADeviceVarODRUsedByHost.insert(Var); + else if (SemaRef.LangOpts.GPURelocatableDeviceCode) + SemaRef.getASTContext().CUDAExternalDeviceDeclODRUsedByHost.insert(Var); } } - 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, DeclContext *DC) { +void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc, + ValueDecl *var) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then @@ -17393,12 +19252,12 @@ 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; @@ -17414,7 +19273,8 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec // private instances of the captured declarations. const Capture &Cap = CSI->getCapture(Var); if (Cap.isCopyCapture() && - !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable) && + !(isa<LambdaScopeInfo>(CSI) && + !cast<LambdaScopeInfo>(CSI)->lambdaCaptureShouldBeConst()) && !(isa<CapturedRegionScopeInfo>(CSI) && cast<CapturedRegionScopeInfo>(CSI)->CapRegionKind == CR_OpenMP)) DeclRefType.addConst(); @@ -17425,14 +19285,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, DC); + + VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl(); + if (Underlying) { + if (Underlying->hasLocalStorage() && Diagnose) + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); } return nullptr; } @@ -17440,9 +19304,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); @@ -17499,17 +19366,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. @@ -17573,10 +19451,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) { @@ -17615,16 +19492,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; @@ -17634,6 +19507,22 @@ 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; + } + + if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() && + CaptureType.getNonReferenceType().isWebAssemblyReferenceType()) { + S.Diag(Loc, diag::err_wasm_ca_reference) << 0; + Invalid = true; + } + // Compute the type of the field that will capture this variable. if (ByRef) { // C++11 [expr.prim.lambda]p15: @@ -17702,7 +19591,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // declared const (9.3.1) if and only if the lambda-expression's // parameter-declaration-clause is not followed by mutable. DeclRefType = CaptureType.getNonReferenceType(); - if (!LSI->Mutable && !CaptureType->isReferenceType()) + bool Const = LSI->lambdaCaptureShouldBeConst(); + if (Const && !CaptureType->isReferenceType()) DeclRefType.addConst(); } @@ -17714,7 +19604,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; @@ -17740,7 +19631,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. @@ -17816,16 +19707,30 @@ 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(); - DeclContext *DC = CurContext; + + // tryCaptureVariable is called every time a DeclRef is formed, + // it can therefore have non-negigible impact on performances. + // For local variables and when there is no capturing scope, + // we can bailout early. + if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC)) + return true; + + 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"); + const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // We need to sync up the Declaration Context with the @@ -17838,19 +19743,16 @@ bool Sema::tryCaptureVariable( } } - - // If the variable is declared in the current context, there is no need to - // capture it. - if (VarDC == DC) return true; - // Capture global variables if it is required to use private copy of this // variable. - 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 @@ -17866,12 +19768,34 @@ bool Sema::tryCaptureVariable( bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; do { + + LambdaScopeInfo *LSI = nullptr; + if (!FunctionScopes.empty()) + LSI = dyn_cast_or_null<LambdaScopeInfo>( + FunctionScopes[FunctionScopesIndex]); + + bool IsInScopeDeclarationContext = + !LSI || LSI->AfterParameterList || CurContext == LSI->CallOperator; + + if (LSI && !LSI->AfterParameterList) { + // This allows capturing parameters from a default value which does not + // seems correct + if (isa<ParmVarDecl>(Var) && !Var->getDeclContext()->isFunctionOrMethod()) + return true; + } + // If the variable is declared in the current context, there is no need to + // capture it. + if (IsInScopeDeclarationContext && + FunctionScopesIndex == MaxFunctionScopesIndex && VarDC == DC) + return true; + // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. - DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var, - ExprLoc, - BuildAndDiagnose, - *this); + DeclContext *ParentDC = + !IsInScopeDeclarationContext + ? DC->getParent() + : getParentOfCapturingContextOrNull(DC, Var, ExprLoc, + BuildAndDiagnose, *this); // We need to check for the parent *first* because, if we *have* // private-captured a global variable, we need to recursively capture it in // intermediate blocks, lambdas, etc. @@ -17886,13 +19810,20 @@ bool Sema::tryCaptureVariable( FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI); - // Check whether we've already captured it. if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, DeclRefType)) { CSI->getCapture(Var).markUsed(BuildAndDiagnose); break; } + + // When evaluating some attributes (like enable_if) we might refer to a + // function parameter appertaining to the same declaration as that + // attribute. + if (const auto *Parm = dyn_cast<ParmVarDecl>(Var); + Parm && Parm->getDeclContext() == DC) + return true; + // If we are instantiating a generic lambda call operator body, // we do not want to capture new variables. What was captured // during either a lambdas transformation or initial parsing @@ -17906,7 +19837,7 @@ bool Sema::tryCaptureVariable( Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl); buildLambdaCaptureFixit(*this, LSI, Var); } else - diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC); + diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var); } return true; } @@ -18002,10 +19933,10 @@ bool Sema::tryCaptureVariable( } return true; } - - FunctionScopesIndex--; - DC = ParentDC; Explicit = false; + FunctionScopesIndex--; + if (IsInScopeDeclarationContext) + DC = ParentDC; } while (!VarDC->Equals(DC)); // Walk back down the scope stack, (e.g. from outer lambda to inner lambda) @@ -18054,7 +19985,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; @@ -18063,7 +19994,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(), @@ -18071,7 +20002,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; @@ -18270,7 +20201,6 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR); - return ExprEmpty(); } case Expr::BinaryOperatorClass: { @@ -18358,9 +20288,15 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, } } + void *ExOrTy = nullptr; + bool IsExpr = GSE->isExprPredicate(); + if (IsExpr) + ExOrTy = GSE->getControllingExpr(); + else + ExOrTy = GSE->getControllingType(); return AnyChanged ? S.CreateGenericSelectionExpr( GSE->getGenericLoc(), GSE->getDefaultLoc(), - GSE->getRParenLoc(), GSE->getControllingExpr(), + GSE->getRParenLoc(), IsExpr, ExOrTy, GSE->getAssocTypeSourceInfos(), AssocExprs) : ExprEmpty(); } @@ -18494,6 +20430,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) { @@ -18576,14 +20544,31 @@ static void DoMarkVarDeclReferenced( DRE->setDecl(DRE->getDecl()); else if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) ME->setMemberDecl(ME->getMemberDecl()); - } else if (FirstInstantiation || - isa<VarTemplateSpecializationDecl>(Var)) { + } else if (FirstInstantiation) { + SemaRef.PendingInstantiations + .push_back(std::make_pair(Var, PointOfInstantiation)); + } else { + bool Inserted = false; + for (auto &I : SemaRef.SavedPendingInstantiations) { + auto Iter = llvm::find_if( + I, [Var](const Sema::PendingImplicitInstantiation &P) { + return P.first == Var; + }); + if (Iter != I.end()) { + SemaRef.PendingInstantiations.push_back(*Iter); + I.erase(Iter); + Inserted = true; + break; + } + } + // 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 + if (isa<VarTemplateSpecializationDecl>(Var) && !Inserted) + SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); } } @@ -18617,7 +20602,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; @@ -18640,34 +20628,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. @@ -18675,6 +20660,34 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { DoMarkVarDeclReferenced(*this, Loc, Var, nullptr, RefsMinusAssignments); } +// C++ [temp.dep.expr]p3: +// An id-expression is type-dependent if it contains: +// - an identifier associated by name lookup with an entity captured by copy +// in a lambda-expression that has an explicit object parameter whose type +// is dependent ([dcl.fct]), +static void FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter( + Sema &SemaRef, ValueDecl *D, Expr *E) { + auto *ID = dyn_cast<DeclRefExpr>(E); + if (!ID || ID->isTypeDependent()) + return; + + auto IsDependent = [&]() { + const LambdaScopeInfo *LSI = SemaRef.getCurLambda(); + if (!LSI) + return false; + if (!LSI->ExplicitObjectParameter || + !LSI->ExplicitObjectParameter->getType()->isDependentType()) + return false; + if (!LSI->CaptureMap.count(D)) + return false; + const Capture &Cap = LSI->getCapture(D); + return !Cap.isCopyCapture(); + }(); + + ID->setCapturedByCopyInLambdaWithExplicitObjectParameter( + IsDependent, SemaRef.getASTContext()); +} + static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, bool MightBeOdrUse, @@ -18684,9 +20697,19 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, if (VarDecl *Var = dyn_cast<VarDecl>(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E, RefsMinusAssignments); + if (SemaRef.getLangOpts().CPlusPlus) + FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(SemaRef, + Var, E); return; } + if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) { + DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E); + if (SemaRef.getLangOpts().CPlusPlus) + FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(SemaRef, + 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 @@ -18725,10 +20748,14 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; - if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) - if (!isConstantEvaluated() && FD->isConsteval() && - !RebuildingImmediateInvocation) + if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) { + if (!isUnevaluatedContext() && !isConstantEvaluatedContext() && + !isImmediateFunctionContext() && + !isCheckingDefaultArgumentOrInitializer() && + FD->isImmediateFunction() && !RebuildingImmediateInvocation && + !FD->isDependentContext()) ExprEvalContexts.back().ReferenceToConsteval.insert(E); + } MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); } @@ -18744,7 +20771,7 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { bool MightBeOdrUse = true; if (E->performsVirtualDispatch(getLangOpts())) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) - if (Method->isPure()) + if (Method->isPureVirtual()) MightBeOdrUse = false; } SourceLocation Loc = @@ -18829,14 +20856,27 @@ class EvaluatedExprMarker : public UsedDeclVisitor<EvaluatedExprMarker> { public: typedef UsedDeclVisitor<EvaluatedExprMarker> Inherited; bool SkipLocalVariables; + ArrayRef<const Expr *> StopAt; - EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) - : Inherited(S), SkipLocalVariables(SkipLocalVariables) {} + EvaluatedExprMarker(Sema &S, bool SkipLocalVariables, + ArrayRef<const Expr *> StopAt) + : Inherited(S), SkipLocalVariables(SkipLocalVariables), StopAt(StopAt) {} void visitUsedDecl(SourceLocation Loc, Decl *D) { S.MarkFunctionReferenced(Loc, cast<FunctionDecl>(D)); } + void Visit(Expr *E) { + if (llvm::is_contained(StopAt, E)) + return; + Inherited::Visit(E); + } + + void VisitConstantExpr(ConstantExpr *E) { + // Don't mark declarations within a ConstantExpression, as this expression + // will be evaluated and folded to a value. + } + void VisitDeclRefExpr(DeclRefExpr *E) { // If we were asked not to visit local variables, don't. if (SkipLocalVariables) { @@ -18863,9 +20903,43 @@ public: /// /// \param SkipLocalVariables If true, don't mark local variables as /// 'referenced'. +/// \param StopAt Subexpressions that we shouldn't recurse into. void Sema::MarkDeclarationsReferencedInExpr(Expr *E, - bool SkipLocalVariables) { - EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E); + bool SkipLocalVariables, + ArrayRef<const Expr*> StopAt) { + EvaluatedExprMarker(*this, SkipLocalVariables, StopAt).Visit(E); +} + +/// Emit a diagnostic when statements are reachable. +/// FIXME: check for reachability even in expressions for which we don't build a +/// CFG (eg, in the initializer of a global or in a constant expression). +/// For example, +/// namespace { auto *p = new double[3][false ? (1, 2) : 3]; } +bool Sema::DiagIfReachable(SourceLocation Loc, ArrayRef<const Stmt *> Stmts, + const PartialDiagnostic &PD) { + if (!Stmts.empty() && getCurFunctionOrMethodDecl()) { + if (!FunctionScopes.empty()) + FunctionScopes.back()->PossiblyUnreachableDiags.push_back( + sema::PossiblyUnreachableDiag(PD, Loc, Stmts)); + return true; + } + + // 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())) + return false; + // 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; } /// Emit a diagnostic that describes an effect on the run-time behavior @@ -18886,6 +20960,10 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E, /// during overload resolution or within sizeof/alignof/typeof/typeid. bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, const PartialDiagnostic &PD) { + + if (ExprEvalContexts.back().isDiscardedStatementContext()) + return false; + switch (ExprEvalContexts.back().Context) { case ExpressionEvaluationContext::Unevaluated: case ExpressionEvaluationContext::UnevaluatedList: @@ -18895,33 +20973,13 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, break; case ExpressionEvaluationContext::ConstantEvaluated: + case ExpressionEvaluationContext::ImmediateFunctionContext: // Relevant diagnostics should be produced by constant evaluation. break; case ExpressionEvaluationContext::PotentiallyEvaluated: case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: - if (!Stmts.empty() && getCurFunctionOrMethodDecl()) { - FunctionScopes.back()->PossiblyUnreachableDiags. - push_back(sema::PossiblyUnreachableDiag(PD, Loc, Stmts)); - return true; - } - - // 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; + return DiagIfReachable(Loc, Stmts, PD); } return false; @@ -18930,7 +20988,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, @@ -19093,10 +21151,12 @@ ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E, } Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc, - Expr *SubExpr, ConditionKind CK) { - // Empty conditions are valid in for-statements. + Expr *SubExpr, ConditionKind CK, + bool MissingOK) { + // MissingOK indicates whether having no condition expression is valid + // (for loop) or invalid (e.g. while loop). if (!SubExpr) - return ConditionResult(); + return MissingOK ? ConditionResult() : ConditionError(); ExprResult Cond; switch (CK) { @@ -19114,7 +21174,7 @@ Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc, } if (Cond.isInvalid()) { Cond = CreateRecoveryExpr(SubExpr->getBeginLoc(), SubExpr->getEndLoc(), - {SubExpr}); + {SubExpr}, PreferredConditionType(CK)); if (!Cond.get()) return ConditionError(); } @@ -19371,14 +21431,7 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) { if (ParamTypes.empty() && Proto->isVariadic()) { // the special case ArgTypes.reserve(E->getNumArgs()); for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { - Expr *Arg = E->getArg(i); - QualType ArgType = Arg->getType(); - if (E->isLValue()) { - ArgType = S.Context.getLValueReferenceType(ArgType); - } else if (E->isXValue()) { - ArgType = S.Context.getRValueReferenceType(ArgType); - } - ArgTypes.push_back(ArgType); + ArgTypes.push_back(S.Context.getReferenceQualifiedType(E->getArg(i))); } ParamTypes = ArgTypes; } @@ -19505,7 +21558,8 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { FunctionDecl *NewFD = FunctionDecl::Create( S.Context, FD->getDeclContext(), Loc, Loc, FD->getNameInfo().getName(), DestType, FD->getTypeSourceInfo(), - SC_None, false /*isInlineSpecified*/, FD->hasPrototype(), + SC_None, S.getCurFPFeatures().isFPConstrained(), + false /*isInlineSpecified*/, FD->hasPrototype(), /*ConstexprKind*/ ConstexprSpecKind::Unspecified); if (FD->getQualifier()) @@ -19726,7 +21780,8 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()); if (DRE) { auto *FD = cast<FunctionDecl>(DRE->getDecl()); - if (FD->getBuiltinID() == Builtin::BI__noop) { + unsigned BuiltinID = FD->getBuiltinID(); + if (BuiltinID == Builtin::BI__noop) { E = ImpCastExprToType(E, Context.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr) .get(); @@ -19734,6 +21789,36 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { VK_PRValue, SourceLocation(), FPOptionsOverride()); } + + if (Context.BuiltinInfo.isInStdNamespace(BuiltinID)) { + // Any use of these other than a direct call is ill-formed as of C++20, + // because they are not addressable functions. In earlier language + // modes, warn and force an instantiation of the real body. + Diag(E->getBeginLoc(), + getLangOpts().CPlusPlus20 + ? diag::err_use_of_unaddressable_function + : diag::warn_cxx20_compat_use_of_unaddressable_function); + if (FD->isImplicitlyInstantiable()) { + // Require a definition here because a normal attempt at + // instantiation for a builtin will be ignored, and we won't try + // again later. We assume that the definition of the template + // precedes this use. + InstantiateFunctionDefinition(E->getBeginLoc(), FD, + /*Recursive=*/false, + /*DefinitionRequired=*/true, + /*AtEndOfTU=*/false); + } + // Produce a properly-typed reference to the function. + CXXScopeSpec SS; + SS.Adopt(DRE->getQualifierLoc()); + TemplateArgumentListInfo TemplateArgs; + DRE->copyTemplateArgumentsInto(TemplateArgs); + return BuildDeclRefExpr( + FD, FD->getType(), VK_LValue, DRE->getNameInfo(), + DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(), + DRE->getTemplateKeywordLoc(), + DRE->hasExplicitTemplateArgs() ? &TemplateArgs : nullptr); + } } Diag(E->getBeginLoc(), diag::err_builtin_fn_use); @@ -19774,6 +21859,8 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" +#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/WebAssemblyReferenceTypes.def" #define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id: #define PLACEHOLDER_TYPE(Id, SingletonId) #include "clang/AST/BuiltinTypes.def" @@ -19815,7 +21902,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; }); @@ -19827,7 +21915,7 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( }); } if (Spec == AvailSpecs.end()) - return None; + return std::nullopt; return Spec->getVersion(); }; |