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