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