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.cpp1159
1 files changed, 792 insertions, 367 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4746355e9800..60abd718e228 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -37,6 +37,7 @@
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
@@ -47,7 +48,7 @@
using namespace clang;
using namespace sema;
-/// \brief Determine whether the use of this declaration is valid, without
+/// Determine whether the use of this declaration is valid, without
/// emitting diagnostics.
bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) {
// See if this is an auto-typed variable whose initializer we are parsing.
@@ -88,7 +89,7 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
}
}
-/// \brief Emit a note explaining that this function is deleted.
+/// Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
assert(Decl->isDeleted());
@@ -116,7 +117,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
<< Decl << true;
}
-/// \brief Determine whether a FunctionDecl was ever declared with an
+/// Determine whether a FunctionDecl was ever declared with an
/// explicit storage class.
static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
for (auto I : D->redecls()) {
@@ -126,7 +127,7 @@ static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
return false;
}
-/// \brief Check whether we're in an extern inline function and referring to a
+/// Check whether we're in an extern inline function and referring to a
/// variable or function with internal linkage (C11 6.7.4p3).
///
/// This is only a warning because we used to silently accept this code, but
@@ -189,7 +190,7 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
}
}
-/// \brief Determine whether the use of this declaration is valid, and
+/// Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
/// This routine diagnoses various problems with referencing
@@ -201,10 +202,11 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
/// \returns true if there was an error (this declaration cannot be
/// referenced), false otherwise.
///
-bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
+bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
const ObjCInterfaceDecl *UnknownObjCClass,
bool ObjCPropertyAccess,
bool AvoidPartialAvailabilityChecks) {
+ SourceLocation Loc = Locs.front();
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
@@ -288,7 +290,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return true;
}
- DiagnoseAvailabilityOfDecl(D, Loc, UnknownObjCClass, ObjCPropertyAccess,
+ DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess,
AvoidPartialAvailabilityChecks);
DiagnoseUnusedOfDecl(*this, D, Loc);
@@ -298,7 +300,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return false;
}
-/// \brief Retrieve the message suffix that should be added to a
+/// Retrieve the message suffix that should be added to a
/// diagnostic complaining about the given function being deleted or
/// unavailable.
std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
@@ -776,6 +778,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
return VAK_Valid;
}
+ if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct)
+ return VAK_Invalid;
+
if (Ty.isCXX98PODType(Context))
return VAK_Valid;
@@ -837,7 +842,10 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
break;
case VAK_Invalid:
- if (Ty->isObjCObjectType())
+ if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct)
+ Diag(E->getLocStart(),
+ diag::err_cannot_pass_non_trivial_c_struct_to_vararg) << Ty << CT;
+ else if (Ty->isObjCObjectType())
DiagRuntimeBehavior(
E->getLocStart(), nullptr,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
@@ -909,7 +917,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return E;
}
-/// \brief Converts an integer to complex float type. Helper function of
+/// Converts an integer to complex float type. Helper function of
/// UsualArithmeticConversions()
///
/// \return false if the integer expression is an integer type and is
@@ -934,7 +942,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
return false;
}
-/// \brief Handle arithmetic conversion with complex types. Helper function of
+/// Handle arithmetic conversion with complex types. Helper function of
/// UsualArithmeticConversions()
static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
@@ -990,7 +998,7 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
return ResultType;
}
-/// \brief Handle arithmetic conversion from integer to float. Helper function
+/// Handle arithmetic conversion from integer to float. Helper function
/// of UsualArithmeticConversions()
static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
ExprResult &IntExpr,
@@ -1021,7 +1029,7 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
return result;
}
-/// \brief Handle arithmethic conversion with floating point types. Helper
+/// Handle arithmethic conversion with floating point types. Helper
/// function of UsualArithmeticConversions()
static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
@@ -1059,7 +1067,7 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
/*convertFloat=*/!IsCompAssign);
}
-/// \brief Diagnose attempts to convert between __float128 and long double if
+/// Diagnose attempts to convert between __float128 and long double if
/// there is no support for such conversion. Helper function of
/// UsualArithmeticConversions().
static bool unsupportedTypeConversion(const Sema &S, QualType LHSType,
@@ -1092,13 +1100,12 @@ static bool unsupportedTypeConversion(const Sema &S, QualType LHSType,
Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy &&
RHSElemType == S.Context.Float128Ty);
- /* We've handled the situation where __float128 and long double have the same
- representation. The only other allowable conversion is if long double is
- really just double.
- */
+ // We've handled the situation where __float128 and long double have the same
+ // representation. We allow all conversions for all possible long double types
+ // except PPC's double double.
return Float128AndLongDouble &&
- (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) !=
- &llvm::APFloat::IEEEdouble());
+ (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) ==
+ &llvm::APFloat::PPCDoubleDouble());
}
typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType);
@@ -1116,7 +1123,7 @@ ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) {
}
}
-/// \brief Handle integer arithmetic conversions. Helper function of
+/// Handle integer arithmetic conversions. Helper function of
/// UsualArithmeticConversions()
template <PerformCastFn doLHSCast, PerformCastFn doRHSCast>
static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
@@ -1167,7 +1174,7 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
}
}
-/// \brief Handle conversions with GCC complex int extension. Helper function
+/// Handle conversions with GCC complex int extension. Helper function
/// of UsualArithmeticConversions()
static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
@@ -1529,6 +1536,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
CharTy = Context.getWideCharType();
Kind = StringLiteral::Wide;
} else if (Literal.isUTF8()) {
+ if (getLangOpts().Char8)
+ CharTy = Context.Char8Ty;
Kind = StringLiteral::UTF8;
} else if (Literal.isUTF16()) {
CharTy = Context.Char16Ty;
@@ -1545,17 +1554,14 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
CharTyConst.addConst();
+ CharTyConst = Context.adjustStringLiteralBaseType(CharTyConst);
+
// Get an array type for the string, according to C99 6.4.5. This includes
// the nul terminator character as well as the string length for pascal
// strings.
- QualType StrTy = Context.getConstantArrayType(CharTyConst,
- llvm::APInt(32, Literal.GetNumStringChars()+1),
- ArrayType::Normal, 0);
-
- // OpenCL v1.1 s6.5.3: a string literal is in the constant address space.
- if (getLangOpts().OpenCL) {
- StrTy = Context.getAddrSpaceQualType(StrTy, LangAS::opencl_constant);
- }
+ QualType StrTy = Context.getConstantArrayType(
+ CharTyConst, llvm::APInt(32, Literal.GetNumStringChars() + 1),
+ ArrayType::Normal, 0);
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(),
@@ -1674,9 +1680,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
MarkDeclRefReferenced(E);
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
- Ty.getObjCLifetime() == Qualifiers::OCL_Weak &&
+ Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() &&
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart()))
- recordUseOfEvaluatedWeak(E);
+ getCurFunction()->recordUseOfWeak(E);
FieldDecl *FD = dyn_cast<FieldDecl>(D);
if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D))
@@ -1711,7 +1717,7 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgumentListInfo &Buffer,
DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *&TemplateArgs) {
- if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
+ if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId) {
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
@@ -2070,19 +2076,21 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
IsAddressOfOperand, TemplateArgs);
// Perform the required lookup.
- LookupResult R(*this, NameInfo,
- (Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam)
- ? LookupObjCImplicitSelfParam : LookupOrdinaryName);
- if (TemplateArgs) {
+ LookupResult R(*this, NameInfo,
+ (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam)
+ ? LookupObjCImplicitSelfParam
+ : LookupOrdinaryName);
+ if (TemplateKWLoc.isValid() || TemplateArgs) {
// Lookup the template name again to correctly establish the context in
// which it was found. This is really unfortunate as we already did the
// lookup to determine that it was a template name in the first place. If
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
bool MemberOfUnknownSpecialization;
- LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
- MemberOfUnknownSpecialization);
-
+ if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ MemberOfUnknownSpecialization, TemplateKWLoc))
+ return ExprError();
+
if (MemberOfUnknownSpecialization ||
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
@@ -2148,6 +2156,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
if (SS.isValid())
CCC->setTypoNNS(SS.getScopeRep());
}
+ // FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for
+ // 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 ? std::move(CCC) : std::move(DefaultValidator),
nullptr, None, &TE)) {
@@ -2243,7 +2254,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// In C++1y, if this is a variable template id, then check it
// in BuildTemplateIdExpr().
// The single lookup result must be a variable template declaration.
- if (Id.getKind() == UnqualifiedId::IK_TemplateId && Id.TemplateId &&
+ if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId &&
Id.TemplateId->Kind == TNK_Var_template) {
assert(R.getAsSingle<VarTemplateDecl>() &&
"There should only be one declaration found.");
@@ -2401,7 +2412,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo &II = Context.Idents.get("self");
UnqualifiedId SelfName;
SelfName.setIdentifier(&II, SourceLocation());
- SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam);
+ SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
CXXScopeSpec SelfScopeSpec;
SourceLocation TemplateKWLoc;
ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc,
@@ -2425,8 +2436,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IV->getLocation(), SelfExpr.get(), true, true);
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
- recordUseOfEvaluatedWeak(Result);
+ if (!isUnevaluatedContext() &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
+ getCurFunction()->recordUseOfWeak(Result);
}
if (getLangOpts().ObjCAutoRefCount) {
if (CurContext->isClosure())
@@ -2470,7 +2482,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return ExprResult((Expr *)nullptr);
}
-/// \brief Cast a base object to a member's actual type.
+/// Cast a base object to a member's actual type.
///
/// Logically this happens in three phases:
///
@@ -2716,12 +2728,23 @@ static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) {
return false;
}
+// Certain multiversion types should be treated as overloaded even when there is
+// only one result.
+static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) {
+ assert(R.isSingleResult() && "Expected only a single result");
+ const auto *FD = dyn_cast<FunctionDecl>(R.getFoundDecl());
+ return FD &&
+ (FD->isCPUDispatchMultiVersion() || FD->isCPUSpecificMultiVersion());
+}
+
ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R, bool NeedsADL,
bool AcceptInvalidDecl) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
- if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
+ if (!NeedsADL && R.isSingleResult() &&
+ !R.getAsSingle<FunctionTemplateDecl>() &&
+ !ShouldLookupResultBeMultiVersionOverload(R))
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
R.getRepresentativeDecl(), nullptr,
AcceptInvalidDecl);
@@ -2729,7 +2752,7 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// We only need to check the declaration if there's exactly one
// result, because in the overloaded case the results can only be
// functions and function templates.
- if (R.isSingleResult() &&
+ if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) &&
CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl()))
return ExprError();
@@ -2752,7 +2775,7 @@ static void
diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
ValueDecl *var, DeclContext *DC);
-/// \brief Complete semantic analysis for a reference to the given declaration.
+/// Complete semantic analysis for a reference to the given declaration.
ExprResult Sema::BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs,
@@ -2768,9 +2791,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
// Specifically diagnose references to class templates that are missing
// a template argument list.
- Diag(Loc, diag::err_template_decl_ref) << (isa<VarTemplateDecl>(D) ? 1 : 0)
- << Template << SS.getRange();
- Diag(Template->getLocation(), diag::note_template_decl_here);
+ diagnoseMissingTemplateArguments(TemplateName(Template), Loc);
return ExprError();
}
@@ -3033,8 +3054,9 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
unsigned Length = Str.length();
llvm::APInt LengthI(32, Length + 1);
- if (IT == PredefinedExpr::LFunction) {
- ResTy = Context.WideCharTy.withConst();
+ if (IT == PredefinedExpr::LFunction || IT == PredefinedExpr::LFuncSig) {
+ ResTy =
+ Context.adjustStringLiteralBaseType(Context.WideCharTy.withConst());
SmallString<32> RawChars;
ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(),
Str, RawChars);
@@ -3043,7 +3065,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide,
/*Pascal*/ false, ResTy, Loc);
} else {
- ResTy = Context.CharTy.withConst();
+ ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst());
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
@@ -3063,7 +3085,8 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
case tok::kw___FUNCDNAME__: IT = PredefinedExpr::FuncDName; break; // [MS]
case tok::kw___FUNCSIG__: IT = PredefinedExpr::FuncSig; break; // [MS]
- case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
+ case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break; // [MS]
+ case tok::kw_L__FUNCSIG__: IT = PredefinedExpr::LFuncSig; break; // [MS]
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
}
@@ -3085,6 +3108,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
QualType Ty;
if (Literal.isWide())
Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++.
+ else if (Literal.isUTF8() && getLangOpts().Char8)
+ Ty = Context.Char8Ty; // u8'x' -> char8_t when it exists.
else if (Literal.isUTF16())
Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11.
else if (Literal.isUTF32())
@@ -3280,8 +3305,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// operator "" X ("n")
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
- Context.CharTy.withConst(), llvm::APInt(32, Length + 1),
- ArrayType::Normal, 0);
+ Context.adjustStringLiteralBaseType(Context.CharTy.withConst()),
+ llvm::APInt(32, Length + 1), ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
/*Pascal*/false, StrTy, &TokLoc, 1);
@@ -3313,7 +3338,52 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Expr *Res;
- if (Literal.isFloatingLiteral()) {
+ if (Literal.isFixedPointLiteral()) {
+ QualType Ty;
+
+ if (Literal.isAccum) {
+ if (Literal.isHalf) {
+ Ty = Context.ShortAccumTy;
+ } else if (Literal.isLong) {
+ Ty = Context.LongAccumTy;
+ } else {
+ Ty = Context.AccumTy;
+ }
+ } else if (Literal.isFract) {
+ if (Literal.isHalf) {
+ Ty = Context.ShortFractTy;
+ } else if (Literal.isLong) {
+ Ty = Context.LongFractTy;
+ } else {
+ Ty = Context.FractTy;
+ }
+ }
+
+ if (Literal.isUnsigned) Ty = Context.getCorrespondingUnsignedType(Ty);
+
+ bool isSigned = !Literal.isUnsigned;
+ unsigned scale = Context.getFixedPointScale(Ty);
+ unsigned ibits = Context.getFixedPointIBits(Ty);
+ unsigned bit_width = Context.getTypeInfo(Ty).Width;
+
+ llvm::APInt Val(bit_width, 0, isSigned);
+ bool Overflowed = Literal.GetFixedPointValue(Val, scale);
+
+ // Do not use bit_width since some types may have padding like _Fract or
+ // unsigned _Accums if PaddingOnUnsignedFixedPoint is set.
+ auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width);
+ if (Literal.isFract && Val == MaxVal + 1)
+ // Clause 6.4.4 - The value of a constant shall be in the range of
+ // representable values for its type, with exception for constants of a
+ // fract type with a value of exactly 1; such a constant shall denote
+ // the maximal value for the type.
+ --Val;
+ else if (Val.ugt(MaxVal) || Overflowed)
+ Diag(Tok.getLocation(), diag::err_too_large_for_fixed_point);
+
+ Res = FixedPointLiteral::CreateFromRawInt(Context, Val, Ty,
+ Tok.getLocation(), scale);
+ } else if (Literal.isFloatingLiteral()) {
QualType Ty;
if (Literal.isHalf){
if (getOpenCLOptions().isEnabled("cl_khr_fp16"))
@@ -3553,7 +3623,7 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
return false;
}
-/// \brief Check whether E is a pointer from a decayed array type (the decayed
+/// Check whether E is a pointer from a decayed array type (the decayed
/// pointer type is equal to T) and emit a warning if it is.
static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T,
Expr *E) {
@@ -3571,7 +3641,7 @@ static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T,
<< ICE->getSubExpr()->getType();
}
-/// \brief Check the constraints on expression operands to unary type expression
+/// Check the constraints on expression operands to unary type expression
/// and type traits.
///
/// Completes any types necessary and validates the constraints on the operand
@@ -3655,7 +3725,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
return false;
}
-/// \brief Check the constraints on operands to unary expression and type
+/// Check the constraints on operands to unary expression and type
/// traits.
///
/// This will complete any types necessary, and validate the various constraints
@@ -3909,7 +3979,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
} while (!T.isNull() && T->isVariablyModifiedType());
}
-/// \brief Build a sizeof or alignof expression given a type operand.
+/// Build a sizeof or alignof expression given a type operand.
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
SourceLocation OpLoc,
@@ -3953,7 +4023,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd());
}
-/// \brief Build a sizeof or alignof expression given an expression
+/// Build a sizeof or alignof expression given an expression
/// operand.
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
@@ -4071,7 +4141,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
-/// \brief Diagnose if arithmetic on the given ObjC pointer is illegal.
+/// Diagnose if arithmetic on the given ObjC pointer is illegal.
///
/// \return true on error
static bool checkArithmeticOnObjCPointer(Sema &S,
@@ -4327,10 +4397,13 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
// Per C++ core issue 1213, the result is an xvalue if either operand is
// a non-lvalue array, and an lvalue otherwise.
- if (getLangOpts().CPlusPlus11 &&
- ((LHSExp->getType()->isArrayType() && !LHSExp->isLValue()) ||
- (RHSExp->getType()->isArrayType() && !RHSExp->isLValue())))
- VK = VK_XValue;
+ if (getLangOpts().CPlusPlus11) {
+ for (auto *Op : {LHSExp, RHSExp}) {
+ Op = Op->IgnoreImplicit();
+ if (Op->getType()->isArrayType() && !Op->isLValue())
+ VK = VK_XValue;
+ }
+ }
// Perform default conversions.
if (!LHSExp->getType()->getAs<VectorType>()) {
@@ -4391,12 +4464,24 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
} else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
BaseExpr = LHSExp; // vectors: V[123]
IndexExpr = RHSExp;
+ // We apply C++ DR1213 to vector subscripting too.
+ if (getLangOpts().CPlusPlus11 && LHSExp->getValueKind() == VK_RValue) {
+ ExprResult Materialized = TemporaryMaterializationConversion(LHSExp);
+ if (Materialized.isInvalid())
+ return ExprError();
+ LHSExp = Materialized.get();
+ }
VK = LHSExp->getValueKind();
if (VK != VK_RValue)
OK = OK_VectorComponent;
- // FIXME: need to deal with const...
ResultType = VTy->getElementType();
+ QualType BaseType = BaseExpr->getType();
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+ Qualifiers MemberQuals = ResultType.getQualifiers();
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ ResultType = Context.getQualifiedType(ResultType, Combined);
} else if (LHSTy->isArrayType()) {
// If we see an array that wasn't promoted by
// DefaultFunctionArrayLvalueConversion, it must be an array that
@@ -4830,6 +4915,10 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
(!Param || !Param->hasAttr<CFConsumedAttr>()))
CFAudited = true;
+ if (Proto->getExtParameterInfo(i).isNoEscape())
+ if (auto *BE = dyn_cast<BlockExpr>(Arg->IgnoreParenNoopCasts(Context)))
+ BE->getBlockDecl()->setDoesNotEscape();
+
InitializedEntity Entity =
Param ? InitializedEntity::InitializeParameter(Context, Param,
ProtoArgType)
@@ -5495,7 +5584,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// CUDA: Kernel calls must be to global functions
if (FDecl && !FDecl->hasAttr<CUDAGlobalAttr>())
return ExprError(Diag(LParenLoc,diag::err_kern_call_not_global_function)
- << FDecl->getName() << Fn->getSourceRange());
+ << FDecl << Fn->getSourceRange());
// CUDA: Kernel function must have 'void' return type
if (!FuncT->getReturnType()->isVoidType())
@@ -5505,7 +5594,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// CUDA: Calls to global functions must be configured
if (FDecl && FDecl->hasAttr<CUDAGlobalAttr>())
return ExprError(Diag(LParenLoc, diag::err_global_call_not_config)
- << FDecl->getName() << Fn->getSourceRange());
+ << FDecl << Fn->getSourceRange());
}
}
@@ -5704,7 +5793,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
}
// Semantic analysis for initializers is done by ActOnDeclarator() and
- // CheckInitializer() - it requires knowledge of the object being intialized.
+ // CheckInitializer() - it requires knowledge of the object being initialized.
InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
RBraceLoc);
@@ -6238,7 +6327,7 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L,
return expr;
}
-/// \brief Emit a specialized diagnostic when one expression is a null pointer
+/// Emit a specialized diagnostic when one expression is a null pointer
/// constant and the other is not a pointer. Returns true if a diagnostic is
/// emitted.
bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
@@ -6279,7 +6368,7 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
return true;
}
-/// \brief Return false if the condition expression is valid, true otherwise.
+/// Return false if the condition expression is valid, true otherwise.
static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) {
QualType CondTy = Cond->getType();
@@ -6298,7 +6387,7 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) {
return true;
}
-/// \brief Handle when one or both operands are void type.
+/// Handle when one or both operands are void type.
static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
ExprResult &RHS) {
Expr *LHSExpr = LHS.get();
@@ -6315,7 +6404,7 @@ static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
return S.Context.VoidTy;
}
-/// \brief Return false if the NullExpr can be promoted to PointerTy,
+/// Return false if the NullExpr can be promoted to PointerTy,
/// true otherwise.
static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
QualType PointerTy) {
@@ -6328,7 +6417,7 @@ static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
return false;
}
-/// \brief Checks compatibility between two pointers and return the resulting
+/// Checks compatibility between two pointers and return the resulting
/// type.
static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
ExprResult &RHS,
@@ -6462,7 +6551,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
return ResultTy;
}
-/// \brief Return the resulting type when the operands are both block pointers.
+/// Return the resulting type when the operands are both block pointers.
static QualType checkConditionalBlockPointerCompatibility(Sema &S,
ExprResult &LHS,
ExprResult &RHS,
@@ -6487,7 +6576,7 @@ static QualType checkConditionalBlockPointerCompatibility(Sema &S,
return checkConditionalPointerCompatibility(S, LHS, RHS, Loc);
}
-/// \brief Return the resulting type when the operands are both pointers.
+/// Return the resulting type when the operands are both pointers.
static QualType
checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
ExprResult &RHS,
@@ -6526,7 +6615,7 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
return checkConditionalPointerCompatibility(S, LHS, RHS, Loc);
}
-/// \brief Return false if the first expression is not an integer and the second
+/// Return false if the first expression is not an integer and the second
/// expression is not a pointer, true otherwise.
static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int,
Expr* PointerExpr, SourceLocation Loc,
@@ -6546,7 +6635,7 @@ static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int,
return true;
}
-/// \brief Simple conversion between integer and floating point types.
+/// Simple conversion between integer and floating point types.
///
/// Used when handling the OpenCL conditional operator where the
/// condition is a vector while the other operands are scalar.
@@ -6601,7 +6690,7 @@ static QualType OpenCLArithmeticConversions(Sema &S, ExprResult &LHS,
(S, LHS, RHS, LHSType, RHSType, /*IsCompAssign = */ false);
}
-/// \brief Convert scalar operands to a vector that matches the
+/// Convert scalar operands to a vector that matches the
/// condition in length.
///
/// Used when handling the OpenCL conditional operator where the
@@ -6646,7 +6735,7 @@ OpenCLConvertScalarsToVectors(Sema &S, ExprResult &LHS, ExprResult &RHS,
return VectorTy;
}
-/// \brief Return false if this is a valid OpenCL condition vector
+/// Return false if this is a valid OpenCL condition vector
static bool checkOpenCLConditionVector(Sema &S, Expr *Cond,
SourceLocation QuestionLoc) {
// OpenCL v1.1 s6.11.6 says the elements of the vector must be of
@@ -6661,7 +6750,7 @@ static bool checkOpenCLConditionVector(Sema &S, Expr *Cond,
return true;
}
-/// \brief Return false if the vector condition type and the vector
+/// Return false if the vector condition type and the vector
/// result type are compatible.
///
/// OpenCL v1.1 s6.11.6 requires that both vector types have the same
@@ -6691,7 +6780,7 @@ static bool checkVectorResult(Sema &S, QualType CondTy, QualType VecResTy,
return false;
}
-/// \brief Return the resulting type for the conditional operator in
+/// Return the resulting type for the conditional operator in
/// OpenCL (aka "ternary selection operator", OpenCL v1.1
/// s6.3.i) when the condition is a vector type.
static QualType
@@ -6726,7 +6815,7 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond,
return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc);
}
-/// \brief Return true if the Expr is block type
+/// Return true if the Expr is block type
static bool checkBlockType(Sema &S, const Expr *E) {
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
QualType Ty = CE->getCallee()->getType();
@@ -7049,6 +7138,10 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
E = E->IgnoreImpCasts();
E = E->IgnoreConversionOperator();
E = E->IgnoreImpCasts();
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ E = MTE->GetTemporaryExpr();
+ E = E->IgnoreImpCasts();
+ }
// Built-in binary operator.
if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) {
@@ -7096,6 +7189,8 @@ static bool ExprLooksBoolean(Expr *E) {
return OP->getOpcode() == UO_LNot;
if (E->getType()->isPointerType())
return true;
+ // FIXME: What about overloaded operator calls returning "unspecified boolean
+ // type"s (commonly pointer-to-members)?
return false;
}
@@ -7847,7 +7942,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return Incompatible;
}
-/// \brief Constructs a transparent union from an expression that is
+/// Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
static void ConstructTransparentUnion(Sema &S, ASTContext &C,
ExprResult &EResult, QualType UnionType,
@@ -8014,7 +8109,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
if (Diagnose && isa<ObjCProtocolExpr>(PRE)) {
ObjCProtocolDecl *PDecl = cast<ObjCProtocolExpr>(PRE)->getProtocol();
if (PDecl && !PDecl->hasDefinition()) {
- Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName();
+ Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl;
Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl;
}
}
@@ -8053,18 +8148,57 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
RHS = E;
return Compatible;
}
-
+
if (ConvertRHS)
RHS = ImpCastExprToType(E, Ty, Kind);
}
return result;
}
+namespace {
+/// The original operand to an operator, prior to the application of the usual
+/// arithmetic conversions and converting the arguments of a builtin operator
+/// candidate.
+struct OriginalOperand {
+ explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) {
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Op))
+ Op = MTE->GetTemporaryExpr();
+ if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Op))
+ Op = BTE->getSubExpr();
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(Op)) {
+ Orig = ICE->getSubExprAsWritten();
+ Conversion = ICE->getConversionFunction();
+ }
+ }
+
+ QualType getType() const { return Orig->getType(); }
+
+ Expr *Orig;
+ NamedDecl *Conversion;
+};
+}
+
QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
ExprResult &RHS) {
+ OriginalOperand OrigLHS(LHS.get()), OrigRHS(RHS.get());
+
Diag(Loc, diag::err_typecheck_invalid_operands)
- << LHS.get()->getType() << RHS.get()->getType()
+ << OrigLHS.getType() << OrigRHS.getType()
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+
+ // If a user-defined conversion was applied to either of the operands prior
+ // to applying the built-in operator rules, tell the user about it.
+ if (OrigLHS.Conversion) {
+ Diag(OrigLHS.Conversion->getLocation(),
+ diag::note_typecheck_invalid_operands_converted)
+ << 0 << LHS.get()->getType();
+ }
+ if (OrigRHS.Conversion) {
+ Diag(OrigRHS.Conversion->getLocation(),
+ diag::note_typecheck_invalid_operands_converted)
+ << 1 << RHS.get()->getType();
+ }
+
return QualType();
}
@@ -8215,7 +8349,7 @@ static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int,
QualType IntTy = Int->get()->getType().getUnqualifiedType();
// Determine if the integer constant can be expressed as a floating point
- // number of the appropiate type.
+ // number of the appropriate type.
llvm::APSInt Result;
bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context);
uint64_t Bits = 0;
@@ -8593,7 +8727,7 @@ QualType Sema::CheckRemainderOperands(
return compType;
}
-/// \brief Diagnose invalid arithmetic on two void pointers.
+/// Diagnose invalid arithmetic on two void pointers.
static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
S.Diag(Loc, S.getLangOpts().CPlusPlus
@@ -8603,7 +8737,7 @@ static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
<< RHSExpr->getSourceRange();
}
-/// \brief Diagnose invalid arithmetic on a void pointer.
+/// Diagnose invalid arithmetic on a void pointer.
static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
S.Diag(Loc, S.getLangOpts().CPlusPlus
@@ -8612,7 +8746,7 @@ static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
<< 0 /* one pointer */ << Pointer->getSourceRange();
}
-/// \brief Diagnose invalid arithmetic on a null pointer.
+/// 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.
@@ -8627,7 +8761,7 @@ static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc,
<< S.getLangOpts().CPlusPlus << Pointer->getSourceRange();
}
-/// \brief Diagnose invalid arithmetic on two function pointers.
+/// Diagnose invalid arithmetic on two function pointers.
static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
assert(LHS->getType()->isAnyPointerType());
@@ -8643,7 +8777,7 @@ static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
<< LHS->getSourceRange() << RHS->getSourceRange();
}
-/// \brief Diagnose invalid arithmetic on a function pointer.
+/// Diagnose invalid arithmetic on a function pointer.
static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
assert(Pointer->getType()->isAnyPointerType());
@@ -8655,7 +8789,7 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
<< Pointer->getSourceRange();
}
-/// \brief Emit error if Operand is incomplete pointer type
+/// Emit error if Operand is incomplete pointer type
///
/// \returns True if pointer has incomplete type
static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
@@ -8671,7 +8805,7 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
PointeeTy, Operand->getSourceRange());
}
-/// \brief Check the validity of an arithmetic pointer operand.
+/// Check the validity of an arithmetic pointer operand.
///
/// If the operand has pointer type, this code will check for pointer types
/// which are invalid in arithmetic operations. These will be diagnosed
@@ -8702,7 +8836,7 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
return true;
}
-/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer
+/// Check the validity of a binary arithmetic operation w.r.t. pointer
/// operands.
///
/// This routine will diagnose any invalid arithmetic on pointer operands much
@@ -8804,7 +8938,7 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
Self.Diag(OpLoc, diag::note_string_plus_scalar_silence);
}
-/// \brief Emit a warning when adding a char literal to a string.
+/// Emit a warning when adding a char literal to a string.
static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
const Expr *StringRefExpr = LHSExpr;
@@ -8855,7 +8989,7 @@ static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc,
}
}
-/// \brief Emit error when two pointers are incompatible.
+/// Emit error when two pointers are incompatible.
static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
assert(LHSExpr->getType()->isAnyPointerType());
@@ -9153,7 +9287,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
<< RHS.get()->getSourceRange();
}
-/// \brief Return the resulting type when a vector is shifted
+/// Return the resulting type when a vector is shifted
/// by a scalar or vector shift amount.
static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign) {
@@ -9299,16 +9433,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
return LHSType;
}
-static bool IsWithinTemplateSpecialization(Decl *D) {
- if (DeclContext *DC = D->getDeclContext()) {
- if (isa<ClassTemplateSpecializationDecl>(DC))
- return true;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
- return FD->isFunctionTemplateSpecialization();
- }
- return false;
-}
-
/// If two different enums are compared, raise a warning.
static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
Expr *RHS) {
@@ -9338,7 +9462,7 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
<< LHS->getSourceRange() << RHS->getSourceRange();
}
-/// \brief Diagnose bad pointer comparisons.
+/// Diagnose bad pointer comparisons.
static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS,
bool IsError) {
@@ -9348,7 +9472,7 @@ static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
-/// \brief Returns false if the pointers are converted to a composite type,
+/// Returns false if the pointers are converted to a composite type,
/// true otherwise.
static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS) {
@@ -9586,137 +9710,368 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS,
// Get the decl for a simple expression: a reference to a variable,
// an implicit C++ field reference, or an implicit ObjC ivar reference.
static ValueDecl *getCompareDecl(Expr *E) {
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
return DR->getDecl();
- if (ObjCIvarRefExpr* Ivar = dyn_cast<ObjCIvarRefExpr>(E)) {
+ if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) {
if (Ivar->isFreeIvar())
return Ivar->getDecl();
}
- if (MemberExpr* Mem = dyn_cast<MemberExpr>(E)) {
+ if (MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
if (Mem->isImplicitAccess())
return Mem->getMemberDecl();
}
return nullptr;
}
-// C99 6.5.8, C++ [expr.rel]
-QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
- SourceLocation Loc, BinaryOperatorKind Opc,
- bool IsRelational) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
+/// Diagnose some forms of syntactically-obvious tautological comparison.
+static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS,
+ BinaryOperatorKind Opc) {
+ Expr *LHSStripped = LHS->IgnoreParenImpCasts();
+ Expr *RHSStripped = RHS->IgnoreParenImpCasts();
+
+ QualType LHSType = LHS->getType();
+ QualType RHSType = RHS->getType();
+ if (LHSType->hasFloatingRepresentation() ||
+ (LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) ||
+ LHS->getLocStart().isMacroID() || RHS->getLocStart().isMacroID() ||
+ S.inTemplateInstantiation())
+ return;
- // Handle vector comparisons separately.
- if (LHS.get()->getType()->isVectorType() ||
- RHS.get()->getType()->isVectorType())
- return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational);
+ // Comparisons between two array types are ill-formed for operator<=>, so
+ // we shouldn't emit any additional warnings about it.
+ if (Opc == BO_Cmp && LHSType->isArrayType() && RHSType->isArrayType())
+ return;
+
+ // For non-floating point types, check for self-comparisons of the form
+ // x == x, x != x, x < x, etc. These always evaluate to a constant, and
+ // often indicate logic errors in the program.
+ //
+ // NOTE: Don't warn about comparison expressions resulting from macro
+ // expansion. Also don't warn about comparisons which are only self
+ // comparisons within a template instantiation. The warnings should catch
+ // obvious cases in the definition of the template anyways. The idea is to
+ // warn when the typed comparison operator will always evaluate to the same
+ // result.
+ ValueDecl *DL = getCompareDecl(LHSStripped);
+ ValueDecl *DR = getCompareDecl(RHSStripped);
+ if (DL && DR && declaresSameEntity(DL, DR)) {
+ StringRef Result;
+ switch (Opc) {
+ case BO_EQ: case BO_LE: case BO_GE:
+ Result = "true";
+ break;
+ case BO_NE: case BO_LT: case BO_GT:
+ Result = "false";
+ break;
+ case BO_Cmp:
+ Result = "'std::strong_ordering::equal'";
+ break;
+ default:
+ break;
+ }
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 0 /*self-comparison*/ << !Result.empty()
+ << Result);
+ } else if (DL && DR &&
+ DL->getType()->isArrayType() && DR->getType()->isArrayType() &&
+ !DL->isWeak() && !DR->isWeak()) {
+ // What is it always going to evaluate to?
+ StringRef Result;
+ switch(Opc) {
+ case BO_EQ: // e.g. array1 == array2
+ Result = "false";
+ break;
+ case BO_NE: // e.g. array1 != array2
+ Result = "true";
+ break;
+ default: // e.g. array1 <= array2
+ // The best we can say is 'a constant'
+ break;
+ }
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 1 /*array comparison*/
+ << !Result.empty() << Result);
+ }
+
+ if (isa<CastExpr>(LHSStripped))
+ LHSStripped = LHSStripped->IgnoreParenCasts();
+ if (isa<CastExpr>(RHSStripped))
+ RHSStripped = RHSStripped->IgnoreParenCasts();
+
+ // Warn about comparisons against a string constant (unless the other
+ // operand is null); the user probably wants strcmp.
+ Expr *LiteralString = nullptr;
+ Expr *LiteralStringStripped = nullptr;
+ if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
+ !RHSStripped->isNullPointerConstant(S.Context,
+ Expr::NPC_ValueDependentIsNull)) {
+ LiteralString = LHS;
+ LiteralStringStripped = LHSStripped;
+ } else if ((isa<StringLiteral>(RHSStripped) ||
+ isa<ObjCEncodeExpr>(RHSStripped)) &&
+ !LHSStripped->isNullPointerConstant(S.Context,
+ Expr::NPC_ValueDependentIsNull)) {
+ LiteralString = RHS;
+ LiteralStringStripped = RHSStripped;
+ }
+
+ if (LiteralString) {
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_stringcompare)
+ << isa<ObjCEncodeExpr>(LiteralStringStripped)
+ << LiteralString->getSourceRange());
+ }
+}
+
+static ImplicitConversionKind castKindToImplicitConversionKind(CastKind CK) {
+ switch (CK) {
+ default: {
+#ifndef NDEBUG
+ llvm::errs() << "unhandled cast kind: " << CastExpr::getCastKindName(CK)
+ << "\n";
+#endif
+ llvm_unreachable("unhandled cast kind");
+ }
+ case CK_UserDefinedConversion:
+ return ICK_Identity;
+ case CK_LValueToRValue:
+ return ICK_Lvalue_To_Rvalue;
+ case CK_ArrayToPointerDecay:
+ return ICK_Array_To_Pointer;
+ case CK_FunctionToPointerDecay:
+ return ICK_Function_To_Pointer;
+ case CK_IntegralCast:
+ return ICK_Integral_Conversion;
+ case CK_FloatingCast:
+ return ICK_Floating_Conversion;
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ return ICK_Floating_Integral;
+ case CK_IntegralComplexCast:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralComplexToFloatingComplex:
+ return ICK_Complex_Conversion;
+ case CK_FloatingComplexToReal:
+ case CK_FloatingRealToComplex:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralRealToComplex:
+ return ICK_Complex_Real;
+ }
+}
+
+static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E,
+ QualType FromType,
+ SourceLocation Loc) {
+ // Check for a narrowing implicit conversion.
+ StandardConversionSequence SCS;
+ SCS.setAsIdentityConversion();
+ SCS.setToType(0, FromType);
+ SCS.setToType(1, ToType);
+ if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ SCS.Second = castKindToImplicitConversionKind(ICE->getCastKind());
+
+ APValue PreNarrowingValue;
+ QualType PreNarrowingType;
+ switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
+ PreNarrowingType,
+ /*IgnoreFloatToIntegralConversion*/ true)) {
+ case NK_Dependent_Narrowing:
+ // Implicit conversion to a narrower type, but the expression is
+ // value-dependent so we can't tell whether it's actually narrowing.
+ case NK_Not_Narrowing:
+ return false;
+
+ case NK_Constant_Narrowing:
+ // Implicit conversion to a narrower type, and the value is not a constant
+ // expression.
+ S.Diag(E->getLocStart(), diag::err_spaceship_argument_narrowing)
+ << /*Constant*/ 1
+ << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << ToType;
+ return true;
+
+ case NK_Variable_Narrowing:
+ // Implicit conversion to a narrower type, and the value is not a constant
+ // expression.
+ case NK_Type_Narrowing:
+ S.Diag(E->getLocStart(), diag::err_spaceship_argument_narrowing)
+ << /*Constant*/ 0 << FromType << ToType;
+ // TODO: It's not a constant expression, but what if the user intended it
+ // to be? Can we produce notes to help them figure out why it isn't?
+ return true;
+ }
+ llvm_unreachable("unhandled case in switch");
+}
+
+static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
+ ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc) {
+ using CCT = ComparisonCategoryType;
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
+ // Dig out the original argument type and expression before implicit casts
+ // were applied. These are the types/expressions we need to check the
+ // [expr.spaceship] requirements against.
+ ExprResult LHSStripped = LHS.get()->IgnoreParenImpCasts();
+ ExprResult RHSStripped = RHS.get()->IgnoreParenImpCasts();
+ QualType LHSStrippedType = LHSStripped.get()->getType();
+ QualType RHSStrippedType = RHSStripped.get()->getType();
+
+ // C++2a [expr.spaceship]p3: If one of the operands is of type bool and the
+ // other is not, the program is ill-formed.
+ if (LHSStrippedType->isBooleanType() != RHSStrippedType->isBooleanType()) {
+ S.InvalidOperands(Loc, LHSStripped, RHSStripped);
+ return QualType();
+ }
- Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts();
- Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
+ int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() +
+ RHSStrippedType->isEnumeralType();
+ if (NumEnumArgs == 1) {
+ bool LHSIsEnum = LHSStrippedType->isEnumeralType();
+ QualType OtherTy = LHSIsEnum ? RHSStrippedType : LHSStrippedType;
+ if (OtherTy->hasFloatingRepresentation()) {
+ S.InvalidOperands(Loc, LHSStripped, RHSStripped);
+ return QualType();
+ }
+ }
+ if (NumEnumArgs == 2) {
+ // C++2a [expr.spaceship]p5: If both operands have the same enumeration
+ // type E, the operator yields the result of converting the operands
+ // to the underlying type of E and applying <=> to the converted operands.
+ if (!S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) {
+ S.InvalidOperands(Loc, LHS, RHS);
+ return QualType();
+ }
+ QualType IntType =
+ LHSStrippedType->getAs<EnumType>()->getDecl()->getIntegerType();
+ assert(IntType->isArithmeticType());
- checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
- diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
+ // 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())
+ IntType = S.Context.getPromotedIntegerType(IntType);
- if (!LHSType->hasFloatingRepresentation() &&
- !(LHSType->isBlockPointerType() && IsRelational) &&
- !LHS.get()->getLocStart().isMacroID() &&
- !RHS.get()->getLocStart().isMacroID() &&
- !inTemplateInstantiation()) {
- // For non-floating point types, check for self-comparisons of the form
- // x == x, x != x, x < x, etc. These always evaluate to a constant, and
- // often indicate logic errors in the program.
- //
- // NOTE: Don't warn about comparison expressions resulting from macro
- // expansion. Also don't warn about comparisons which are only self
- // comparisons within a template specialization. The warnings should catch
- // obvious cases in the definition of the template anyways. The idea is to
- // warn when the typed comparison operator will always evaluate to the same
- // result.
- ValueDecl *DL = getCompareDecl(LHSStripped);
- ValueDecl *DR = getCompareDecl(RHSStripped);
- if (DL && DR && DL == DR && !IsWithinTemplateSpecialization(DL)) {
- DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always)
- << 0 // self-
- << (Opc == BO_EQ
- || Opc == BO_LE
- || Opc == BO_GE));
- } else if (DL && DR && LHSType->isArrayType() && RHSType->isArrayType() &&
- !DL->getType()->isReferenceType() &&
- !DR->getType()->isReferenceType()) {
- // what is it always going to eval to?
- char always_evals_to;
- switch(Opc) {
- case BO_EQ: // e.g. array1 == array2
- always_evals_to = 0; // false
- break;
- case BO_NE: // e.g. array1 != array2
- always_evals_to = 1; // true
- break;
- default:
- // best we can say is 'a constant'
- always_evals_to = 2; // e.g. array1 <= array2
- break;
- }
- DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always)
- << 1 // array
- << always_evals_to);
- }
+ LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast);
+ RHS = S.ImpCastExprToType(RHS.get(), IntType, CK_IntegralCast);
+ LHSType = RHSType = IntType;
+ }
+
+ // C++2a [expr.spaceship]p4: If both operands have arithmetic types, the
+ // usual arithmetic conversions are applied to the operands.
+ QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
+ if (Type.isNull())
+ return S.InvalidOperands(Loc, LHS, RHS);
+ assert(Type->isArithmeticType() || Type->isEnumeralType());
+
+ bool HasNarrowing = checkThreeWayNarrowingConversion(
+ S, Type, LHS.get(), LHSType, LHS.get()->getLocStart());
+ HasNarrowing |= checkThreeWayNarrowingConversion(
+ S, Type, RHS.get(), RHSType, RHS.get()->getLocStart());
+ if (HasNarrowing)
+ return QualType();
- if (isa<CastExpr>(LHSStripped))
- LHSStripped = LHSStripped->IgnoreParenCasts();
- if (isa<CastExpr>(RHSStripped))
- RHSStripped = RHSStripped->IgnoreParenCasts();
+ assert(!Type.isNull() && "composite type for <=> has not been set");
- // Warn about comparisons against a string constant (unless the other
- // operand is null), the user probably wants strcmp.
- Expr *literalString = nullptr;
- Expr *literalStringStripped = nullptr;
- if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
- !RHSStripped->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)) {
- literalString = LHS.get();
- literalStringStripped = LHSStripped;
- } else if ((isa<StringLiteral>(RHSStripped) ||
- isa<ObjCEncodeExpr>(RHSStripped)) &&
- !LHSStripped->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)) {
- literalString = RHS.get();
- literalStringStripped = RHSStripped;
+ auto TypeKind = [&]() {
+ if (const ComplexType *CT = Type->getAs<ComplexType>()) {
+ if (CT->getElementType()->hasFloatingRepresentation())
+ return CCT::WeakEquality;
+ return CCT::StrongEquality;
}
+ if (Type->isIntegralOrEnumerationType())
+ return CCT::StrongOrdering;
+ if (Type->hasFloatingRepresentation())
+ return CCT::PartialOrdering;
+ llvm_unreachable("other types are unimplemented");
+ }();
- if (literalString) {
- DiagRuntimeBehavior(Loc, nullptr,
- PDiag(diag::warn_stringcompare)
- << isa<ObjCEncodeExpr>(literalStringStripped)
- << literalString->getSourceRange());
- }
- }
+ return S.CheckComparisonCategoryType(TypeKind, Loc);
+}
+
+static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc,
+ BinaryOperatorKind Opc) {
+ if (Opc == BO_Cmp)
+ return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc);
// C99 6.5.8p3 / C99 6.5.9p4
- UsualArithmeticConversions(LHS, RHS);
+ QualType Type = S.UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+ if (Type.isNull())
+ return S.InvalidOperands(Loc, LHS, RHS);
+ assert(Type->isArithmeticType() || Type->isEnumeralType());
- LHSType = LHS.get()->getType();
- RHSType = RHS.get()->getType();
+ checkEnumComparison(S, Loc, LHS.get(), RHS.get());
+
+ if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
+ return S.InvalidOperands(Loc, LHS, RHS);
+
+ // Check for comparisons of floating point operands using != and ==.
+ if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc))
+ S.CheckFloatComparison(Loc, LHS.get(), RHS.get());
// The result of comparisons is 'bool' in C++, 'int' in C.
- QualType ResultTy = Context.getLogicalOperationType();
+ return S.Context.getLogicalOperationType();
+}
- if (IsRelational) {
- if (LHSType->isRealType() && RHSType->isRealType())
- return ResultTy;
- } else {
- // Check for comparisons of floating point operands using != and ==.
- if (LHSType->hasFloatingRepresentation())
- CheckFloatComparison(Loc, LHS.get(), RHS.get());
+// C99 6.5.8, C++ [expr.rel]
+QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ BinaryOperatorKind Opc) {
+ bool IsRelational = BinaryOperator::isRelationalOp(Opc);
+ bool IsThreeWay = Opc == BO_Cmp;
+ auto IsAnyPointerType = [](ExprResult E) {
+ QualType Ty = E.get()->getType();
+ return Ty->isPointerType() || Ty->isMemberPointerType();
+ };
- if (LHSType->isArithmeticType() && RHSType->isArithmeticType())
- return ResultTy;
+ // C++2a [expr.spaceship]p6: If at least one of the operands is of pointer
+ // type, array-to-pointer, ..., conversions are performed on both operands to
+ // bring them to their composite type.
+ // Otherwise, all comparisons expect an rvalue, so convert to rvalue before
+ // any type-related checks.
+ if (!IsThreeWay || IsAnyPointerType(LHS) || IsAnyPointerType(RHS)) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ if (LHS.isInvalid())
+ return QualType();
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+ if (RHS.isInvalid())
+ return QualType();
+ } else {
+ LHS = DefaultLvalueConversion(LHS.get());
+ if (LHS.isInvalid())
+ return QualType();
+ RHS = DefaultLvalueConversion(RHS.get());
+ if (RHS.isInvalid())
+ return QualType();
}
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
+
+ // Handle vector comparisons separately.
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType())
+ return CheckVectorCompareOperands(LHS, RHS, Loc, Opc);
+
+ diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
+ diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc);
+
+ QualType LHSType = LHS.get()->getType();
+ QualType RHSType = RHS.get()->getType();
+ if ((LHSType->isArithmeticType() || LHSType->isEnumeralType()) &&
+ (RHSType->isArithmeticType() || RHSType->isEnumeralType()))
+ return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc);
+
const Expr::NullPointerConstantKind LHSNullKind =
LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
const Expr::NullPointerConstantKind RHSNullKind =
@@ -9724,6 +10079,44 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
bool LHSIsNull = LHSNullKind != Expr::NPCK_NotNull;
bool RHSIsNull = RHSNullKind != Expr::NPCK_NotNull;
+ auto computeResultTy = [&]() {
+ if (Opc != BO_Cmp)
+ return Context.getLogicalOperationType();
+ assert(getLangOpts().CPlusPlus);
+ assert(Context.hasSameType(LHS.get()->getType(), RHS.get()->getType()));
+
+ QualType CompositeTy = LHS.get()->getType();
+ assert(!CompositeTy->isReferenceType());
+
+ auto buildResultTy = [&](ComparisonCategoryType Kind) {
+ return CheckComparisonCategoryType(Kind, Loc);
+ };
+
+ // C++2a [expr.spaceship]p7: If the composite pointer type is a function
+ // pointer type, a pointer-to-member type, or std::nullptr_t, the
+ // result is of type std::strong_equality
+ if (CompositeTy->isFunctionPointerType() ||
+ CompositeTy->isMemberPointerType() || CompositeTy->isNullPtrType())
+ // FIXME: consider making the function pointer case produce
+ // strong_ordering not strong_equality, per P0946R0-Jax18 discussion
+ // and direction polls
+ return buildResultTy(ComparisonCategoryType::StrongEquality);
+
+ // C++2a [expr.spaceship]p8: If the composite pointer type is an object
+ // pointer type, p <=> q is of type std::strong_ordering.
+ if (CompositeTy->isPointerType()) {
+ // P0946R0: Comparisons between a null pointer constant and an object
+ // pointer result in std::strong_equality
+ if (LHSIsNull != RHSIsNull)
+ return buildResultTy(ComparisonCategoryType::StrongEquality);
+ return buildResultTy(ComparisonCategoryType::StrongOrdering);
+ }
+ // C++2a [expr.spaceship]p9: Otherwise, the program is ill-formed.
+ // TODO: Extend support for operator<=> to ObjC types.
+ return InvalidOperands(Loc, LHS, RHS);
+ };
+
+
if (!IsRelational && LHSIsNull != RHSIsNull) {
bool IsEquality = Opc == BO_EQ;
if (RHSIsNull)
@@ -9751,29 +10144,30 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// conformance with the C++ standard.
diagnoseFunctionPointerToVoidComparison(
*this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
-
+
if (isSFINAEContext())
return QualType();
-
+
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
- return ResultTy;
+ return computeResultTy();
}
// C++ [expr.eq]p2:
// If at least one operand is a pointer [...] bring them to their
// composite pointer type.
+ // C++ [expr.spaceship]p6
+ // If at least one of the operands is of pointer type, [...] bring them
+ // to their composite pointer type.
// C++ [expr.rel]p2:
// If both operands are pointers, [...] bring them to their composite
// pointer type.
if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >=
(IsRelational ? 2 : 1) &&
- (!LangOpts.ObjCAutoRefCount ||
- !(LHSType->isObjCObjectPointerType() ||
- RHSType->isObjCObjectPointerType()))) {
+ (!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() ||
+ RHSType->isObjCObjectPointerType()))) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
- else
- return ResultTy;
+ return computeResultTy();
}
} else if (LHSType->isPointerType() &&
RHSType->isPointerType()) { // C99 6.5.8p2
@@ -9824,7 +10218,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
else
RHS = ImpCastExprToType(RHS.get(), LHSType, Kind);
}
- return ResultTy;
+ return computeResultTy();
}
if (getLangOpts().CPlusPlus) {
@@ -9834,11 +10228,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (!IsRelational && LHSIsNull && RHSIsNull) {
if (LHSType->isNullPtrType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
if (RHSType->isNullPtrType()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
}
@@ -9847,12 +10241,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (!IsRelational && RHSType->isNullPtrType() &&
(LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
if (!IsRelational && LHSType->isNullPtrType() &&
(RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
if (IsRelational &&
@@ -9875,7 +10269,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
else
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
}
}
@@ -9888,15 +10282,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
else
- return ResultTy;
+ return computeResultTy();
}
-
- // Handle scoped enumeration types specifically, since they don't promote
- // to integers.
- if (LHS.get()->getType()->isEnumeralType() &&
- Context.hasSameUnqualifiedType(LHS.get()->getType(),
- RHS.get()->getType()))
- return ResultTy;
}
// Handle block pointer types.
@@ -9912,7 +10299,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
<< RHS.get()->getSourceRange();
}
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
- return ResultTy;
+ return computeResultTy();
}
// Allow block pointers to be compared with null pointer constants.
@@ -9936,7 +10323,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
RHS = ImpCastExprToType(RHS.get(), LHSType,
LHSType->isPointerType() ? CK_BitCast
: CK_AnyPointerToBlockPointerCast);
- return ResultTy;
+ return computeResultTy();
}
if (LHSType->isObjCObjectPointerType() ||
@@ -9969,7 +10356,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
RHS = ImpCastExprToType(E, LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
- return ResultTy;
+ return computeResultTy();
}
if (LHSType->isObjCObjectPointerType() &&
RHSType->isObjCObjectPointerType()) {
@@ -9983,7 +10370,20 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast);
else
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
- return ResultTy;
+ return computeResultTy();
+ }
+
+ if (!IsRelational && LHSType->isBlockPointerType() &&
+ RHSType->isBlockCompatibleObjCPointerType(Context)) {
+ LHS = ImpCastExprToType(LHS.get(), RHSType,
+ CK_BlockPointerToObjCPointerCast);
+ return computeResultTy();
+ } else if (!IsRelational &&
+ LHSType->isBlockCompatibleObjCPointerType(Context) &&
+ RHSType->isBlockPointerType()) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType,
+ CK_BlockPointerToObjCPointerCast);
+ return computeResultTy();
}
}
if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) ||
@@ -10023,30 +10423,30 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
else
RHS = ImpCastExprToType(RHS.get(), LHSType,
RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
- return ResultTy;
+ return computeResultTy();
}
// Handle block pointers.
if (!IsRelational && RHSIsNull
&& LHSType->isBlockPointerType() && RHSType->isIntegerType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
if (!IsRelational && LHSIsNull
&& LHSType->isIntegerType() && RHSType->isBlockPointerType()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
if (getLangOpts().OpenCLVersion >= 200) {
if (LHSIsNull && RHSType->isQueueT()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
if (LHSType->isQueueT() && RHSIsNull) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return ResultTy;
+ return computeResultTy();
}
}
@@ -10100,7 +10500,7 @@ QualType Sema::GetSignedVectorType(QualType V) {
/// types.
QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
- bool IsRelational) {
+ BinaryOperatorKind Opc) {
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false,
@@ -10120,22 +10520,12 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
- if (!LHSType->hasFloatingRepresentation() && !inTemplateInstantiation()) {
- if (DeclRefExpr* DRL
- = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts()))
- if (DeclRefExpr* DRR
- = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParenImpCasts()))
- if (DRL->getDecl() == DRR->getDecl())
- DiagRuntimeBehavior(Loc, nullptr,
- PDiag(diag::warn_comparison_always)
- << 0 // self-
- << 2 // "a constant"
- );
- }
+ diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc);
// Check for comparisons of floating point operands using != and ==.
- if (!IsRelational && LHSType->hasFloatingRepresentation()) {
- assert (RHS.get()->getType()->hasFloatingRepresentation());
+ if (BinaryOperator::isEqualityOp(Opc) &&
+ LHSType->hasFloatingRepresentation()) {
+ assert(RHS.get()->getType()->hasFloatingRepresentation());
CheckFloatComparison(Loc, LHS.get(), RHS.get());
}
@@ -10417,8 +10807,16 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
// Static fields do not inherit constness from parents.
break;
}
- break;
- } // End MemberExpr
+ break; // End MemberExpr
+ } else if (const ArraySubscriptExpr *ASE =
+ dyn_cast<ArraySubscriptExpr>(E)) {
+ E = ASE->getBase()->IgnoreParenImpCasts();
+ continue;
+ } else if (const ExtVectorElementExpr *EVE =
+ dyn_cast<ExtVectorElementExpr>(E)) {
+ E = EVE->getBase()->IgnoreParenImpCasts();
+ continue;
+ }
break;
}
@@ -10659,12 +11057,34 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr,
SourceLocation Loc,
Sema &Sema) {
+ if (Sema.inTemplateInstantiation())
+ return;
+ if (Sema.isUnevaluatedContext())
+ return;
+ if (Loc.isInvalid() || Loc.isMacroID())
+ return;
+ if (LHSExpr->getExprLoc().isMacroID() || RHSExpr->getExprLoc().isMacroID())
+ return;
+
// C / C++ fields
MemberExpr *ML = dyn_cast<MemberExpr>(LHSExpr);
MemberExpr *MR = dyn_cast<MemberExpr>(RHSExpr);
- if (ML && MR && ML->getMemberDecl() == MR->getMemberDecl()) {
- if (isa<CXXThisExpr>(ML->getBase()) && isa<CXXThisExpr>(MR->getBase()))
- Sema.Diag(Loc, diag::warn_identity_field_assign) << 0;
+ if (ML && MR) {
+ if (!(isa<CXXThisExpr>(ML->getBase()) && isa<CXXThisExpr>(MR->getBase())))
+ return;
+ const ValueDecl *LHSDecl =
+ cast<ValueDecl>(ML->getMemberDecl()->getCanonicalDecl());
+ const ValueDecl *RHSDecl =
+ cast<ValueDecl>(MR->getMemberDecl()->getCanonicalDecl());
+ if (LHSDecl != RHSDecl)
+ return;
+ if (LHSDecl->getType().isVolatileQualified())
+ return;
+ if (const ReferenceType *RefTy = LHSDecl->getType()->getAs<ReferenceType>())
+ if (RefTy->getPointeeType().isVolatileQualified())
+ return;
+
+ Sema.Diag(Loc, diag::warn_identity_field_assign) << 0;
}
// Objective-C instance variables
@@ -11045,7 +11465,7 @@ namespace {
AO_No_Error = 4
};
}
-/// \brief Diagnose invalid operand for address of operations.
+/// Diagnose invalid operand for address of operations.
///
/// \param Type The type of operand which cannot have its address taken.
static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
@@ -11418,12 +11838,13 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
}
/// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself.
-/// This warning is only emitted for builtin assignment operations. It is also
-/// suppressed in the event of macro expansions.
+/// This warning suppressed in the event of macro expansions.
static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
- SourceLocation OpLoc) {
+ SourceLocation OpLoc, bool IsBuiltin) {
if (S.inTemplateInstantiation())
return;
+ if (S.isUnevaluatedContext())
+ return;
if (OpLoc.isInvalid() || OpLoc.isMacroID())
return;
LHSExpr = LHSExpr->IgnoreParenImpCasts();
@@ -11446,9 +11867,10 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
if (RefTy->getPointeeType().isVolatileQualified())
return;
- S.Diag(OpLoc, diag::warn_self_assignment)
- << LHSDeclRef->getType()
- << LHSExpr->getSourceRange() << RHSExpr->getSourceRange();
+ S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin
+ : diag::warn_self_assignment_overloaded)
+ << LHSDeclRef->getType() << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
}
/// Check if a bitwise-& is performed on an Objective-C pointer. This
@@ -11583,8 +12005,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
// C++11 5.17p9:
// The meaning of x = {v} [...] is that of x = T(v) [...]. The meaning
// of x = {} is x = T().
- InitializationKind Kind =
- InitializationKind::CreateDirectList(RHSExpr->getLocStart());
+ InitializationKind Kind = InitializationKind::CreateDirectList(
+ RHSExpr->getLocStart(), RHSExpr->getLocStart(), RHSExpr->getLocEnd());
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(LHSExpr->getType());
InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr);
@@ -11641,7 +12063,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
OK = LHS.get()->getObjectKind();
}
if (!ResultTy.isNull()) {
- DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
+ DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true);
DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc);
}
RecordModifiableNonNullParam(*this, LHS.get());
@@ -11677,19 +12099,17 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_GE:
case BO_GT:
ConvertHalfVec = true;
- ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_EQ:
case BO_NE:
ConvertHalfVec = true;
- ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false);
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc);
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;
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc);
+ assert(ResultTy.isNull() || ResultTy->getAsCXXRecordDecl());
break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
@@ -11739,7 +12159,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_AndAssign:
case BO_OrAssign: // fallthrough
- DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
+ DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true);
LLVM_FALLTHROUGH;
case BO_XorAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
@@ -11857,7 +12277,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
ParensRange);
}
-/// \brief It accepts a '&&' expr that is inside a '||' one.
+/// It accepts a '&&' expr that is inside a '||' one.
/// Emit a diagnostic together with a fixit hint that wraps the '&&' expression
/// in parentheses.
static void
@@ -11872,7 +12292,7 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
Bop->getSourceRange());
}
-/// \brief Returns true if the given expression can be evaluated as a constant
+/// Returns true if the given expression can be evaluated as a constant
/// 'true'.
static bool EvaluatesAsTrue(Sema &S, Expr *E) {
bool Res;
@@ -11880,7 +12300,7 @@ static bool EvaluatesAsTrue(Sema &S, Expr *E) {
E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res;
}
-/// \brief Returns true if the given expression can be evaluated as a constant
+/// Returns true if the given expression can be evaluated as a constant
/// 'false'.
static bool EvaluatesAsFalse(Sema &S, Expr *E) {
bool Res;
@@ -11888,7 +12308,7 @@ static bool EvaluatesAsFalse(Sema &S, Expr *E) {
E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res;
}
-/// \brief Look for '&&' in the left hand of a '||' expr.
+/// 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)) {
@@ -11910,7 +12330,7 @@ static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc,
}
}
-/// \brief Look for '&&' in the right hand of a '||' expr.
+/// Look for '&&' in the right hand of a '||' expr.
static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) {
@@ -11925,7 +12345,7 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
}
}
-/// \brief Look for bitwise op in the left or right hand of a bitwise op with
+/// Look for bitwise op in the left or right hand of a bitwise op with
/// lower precedence and emit a diagnostic together with a fixit hint that wraps
/// the '&' expression in parentheses.
static void DiagnoseBitwiseOpInBitwiseOp(Sema &S, BinaryOperatorKind Opc,
@@ -12038,6 +12458,21 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHS, Expr *RHS) {
+ switch (Opc) {
+ case BO_Assign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_SubAssign:
+ case BO_AndAssign:
+ case BO_OrAssign:
+ case BO_XorAssign:
+ DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false);
+ CheckIdentityFieldAssignment(LHS, RHS, OpLoc, S);
+ break;
+ default:
+ break;
+ }
+
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
@@ -12160,6 +12595,16 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
}
+static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
+ if (T.isNull() || T->isDependentType())
+ return false;
+
+ if (!T->isPromotableIntegerType())
+ return true;
+
+ return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy);
+}
+
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
UnaryOperatorKind Opc,
Expr *InputExpr) {
@@ -12167,6 +12612,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
QualType resultType;
+ bool CanOverflow = false;
+
bool ConvertHalfVec = false;
if (getLangOpts().OpenCL) {
QualType Ty = InputExpr->getType();
@@ -12192,6 +12639,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_PostInc,
Opc == UO_PreInc ||
Opc == UO_PreDec);
+ CanOverflow = isOverflowingIntegerType(Context, resultType);
break;
case UO_AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -12205,6 +12653,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
case UO_Plus:
case UO_Minus:
+ CanOverflow = Opc == UO_Minus &&
+ isOverflowingIntegerType(Context, Input.get()->getType());
Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid()) return ExprError();
// Unary plus and minus require promoting an operand of half vector to a
@@ -12241,6 +12691,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Input.isInvalid())
return ExprError();
resultType = Input.get()->getType();
+
if (resultType->isDependentType())
break;
// C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
@@ -12337,7 +12788,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
OK = Input.get()->getObjectKind();
break;
case UO_Coawait:
- // It's unnessesary to represent the pass-through operator co_await in the
+ // It's unnecessary to represent the pass-through operator co_await in the
// AST; just return the input expression instead.
assert(!Input.get()->getType()->isDependentType() &&
"the co_await expression must be non-dependant before "
@@ -12355,17 +12806,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
CheckArrayAccess(Input.get());
auto *UO = new (Context)
- UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc);
+ UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow);
// 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
+/// Determine whether the given expression is a qualified member
/// access expression, of a form that could be turned into a pointer to member
/// with the address-of operator.
-static bool isQualifiedMemberAccess(Expr *E) {
+bool Sema::isQualifiedMemberAccess(Expr *E) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
if (!DRE->getQualifier())
return false;
@@ -12548,11 +12999,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
LastExpr = rebuiltLastStmt;
} else {
LastExpr = PerformCopyInitialization(
- InitializedEntity::InitializeResult(LPLoc,
- Ty,
- false),
- SourceLocation(),
- LastExpr);
+ InitializedEntity::InitializeStmtExprResult(LPLoc, Ty),
+ SourceLocation(), LastExpr);
}
if (LastExpr.isInvalid())
@@ -12783,7 +13231,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
CondExpr = CondICE.get();
CondIsTrue = condEval.getZExtValue();
- // If the condition is > zero, then the AST type is the same as the LSHExpr.
+ // If the condition is > zero, then the AST type is the same as the LHSExpr.
Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr;
resType = ActiveExpr->getType();
@@ -12834,7 +13282,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
Scope *CurScope) {
assert(ParamInfo.getIdentifier() == nullptr &&
"block-id should have no identifier!");
- assert(ParamInfo.getContext() == Declarator::BlockLiteralContext);
+ assert(ParamInfo.getContext() == DeclaratorContext::BlockLiteralContext);
BlockScopeInfo *CurBlock = getCurBlock();
TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope);
@@ -12989,7 +13437,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// Set the captured variables on the block.
// FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
SmallVector<BlockDecl::Capture, 4> Captures;
- for (CapturingScopeInfo::Capture &Cap : BSI->Captures) {
+ for (Capture &Cap : BSI->Captures) {
if (Cap.isThisCapture())
continue;
BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
@@ -13069,7 +13517,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
for (const auto &CI : Result->getBlockDecl()->captures()) {
const VarDecl *var = CI.getVariable();
if (var->getType().isDestructedType() != QualType::DK_none) {
- getCurFunction()->setHasBranchProtectedScope();
+ setFunctionHasBranchProtectedScope();
break;
}
}
@@ -13335,7 +13783,6 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
DiagKind = diag::err_typecheck_incompatible_address_space;
break;
-
} else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) {
DiagKind = diag::err_typecheck_incompatible_ownership;
break;
@@ -13459,7 +13906,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (DiagKind == diag::warn_incompatible_qualified_id &&
PDecl && IFace && !IFace->hasDefinition())
Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id)
- << IFace->getName() << PDecl->getName();
+ << IFace << PDecl;
if (SecondType == Context.OverloadTy)
NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression,
@@ -13700,22 +14147,22 @@ ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) {
}
void
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
- Decl *LambdaContextDecl,
- bool IsDecltype) {
+Sema::PushExpressionEvaluationContext(
+ ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl,
+ ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
- LambdaContextDecl, IsDecltype);
+ LambdaContextDecl, ExprContext);
Cleanup.reset();
if (!MaybeODRUseExprs.empty())
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
void
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
- ReuseLambdaContextDecl_t,
- bool IsDecltype) {
+Sema::PushExpressionEvaluationContext(
+ ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t,
+ ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl;
- PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype);
+ PushExpressionEvaluationContext(NewContext, ClosureContextDecl, ExprContext);
}
void Sema::PopExpressionEvaluationContext() {
@@ -13723,30 +14170,30 @@ void Sema::PopExpressionEvaluationContext() {
unsigned NumTypos = Rec.NumTypos;
if (!Rec.Lambdas.empty()) {
- if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
+ using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind;
+ if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument || Rec.isUnevaluated() ||
+ (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17)) {
unsigned D;
if (Rec.isUnevaluated()) {
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
// (Clause 5).
D = diag::err_lambda_unevaluated_operand;
- } else {
+ } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17) {
// C++1y [expr.const]p2:
// A conditional-expression e is a core constant expression unless the
// evaluation of e, following the rules of the abstract machine, would
// evaluate [...] a lambda-expression.
D = diag::err_lambda_in_constant_expression;
- }
+ } else if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument) {
+ // C++17 [expr.prim.lamda]p2:
+ // A lambda-expression shall not appear [...] in a template-argument.
+ D = diag::err_lambda_in_invalid_context;
+ } else
+ llvm_unreachable("Couldn't infer lambda error message.");
- // C++1z allows lambda expressions as core constant expressions.
- // FIXME: In C++1z, reinstate the restrictions on lambda expressions (CWG
- // 1607) from appearing within template-arguments and array-bounds that
- // 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().CPlusPlus17)
- for (const auto *L : Rec.Lambdas)
- Diag(L->getLocStart(), D);
+ for (const auto *L : Rec.Lambdas)
+ Diag(L->getLocStart(), D);
} else {
// Mark the capture expressions odr-used. This was deferred
// during lambda expression creation.
@@ -13805,13 +14252,13 @@ static bool isEvaluatableContext(Sema &SemaRef) {
switch (SemaRef.ExprEvalContexts.back().Context) {
case Sema::ExpressionEvaluationContext::Unevaluated:
case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
- case Sema::ExpressionEvaluationContext::DiscardedStatement:
// Expressions in this context are never evaluated.
return false;
case Sema::ExpressionEvaluationContext::UnevaluatedList:
case Sema::ExpressionEvaluationContext::ConstantEvaluated:
case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
+ case Sema::ExpressionEvaluationContext::DiscardedStatement:
// Expressions in this context could be evaluated.
return true;
@@ -13855,7 +14302,7 @@ static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
(Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided()));
}
-/// \brief Mark a function referenced, and check whether it is odr-used
+/// Mark a function referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3)
void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
bool MightBeOdrUse) {
@@ -14088,7 +14535,7 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec
// Similarly to mutable captures in lambda, all the OpenMP captures by copy
// are mutable in the sense that user can change their value - they are
// private instances of the captured declarations.
- const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
+ const Capture &Cap = CSI->getCapture(Var);
if (Cap.isCopyCapture() &&
!(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable) &&
!(isa<CapturedRegionScopeInfo>(CSI) &&
@@ -14241,30 +14688,6 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
if (BuildAndDiagnose) {
SourceLocation VarLoc = Var->getLocation();
S.Diag(Loc, diag::warn_block_capture_autoreleasing);
- {
- auto AddAutoreleaseNote =
- S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing);
- // Provide a fix-it for the '__autoreleasing' keyword at the
- // appropriate location in the variable's type.
- if (const auto *TSI = Var->getTypeSourceInfo()) {
- PointerTypeLoc PTL =
- TSI->getTypeLoc().getAsAdjusted<PointerTypeLoc>();
- if (PTL) {
- SourceLocation Loc = PTL.getPointeeLoc().getEndLoc();
- Loc = Lexer::getLocForEndOfToken(Loc, 0, S.getSourceManager(),
- S.getLangOpts());
- if (Loc.isValid()) {
- StringRef CharAtLoc = Lexer::getSourceText(
- CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(1)),
- S.getSourceManager(), S.getLangOpts());
- AddAutoreleaseNote << FixItHint::CreateInsertion(
- Loc, CharAtLoc.empty() || !isWhitespace(CharAtLoc[0])
- ? " __autoreleasing "
- : " __autoreleasing");
- }
- }
- }
- }
S.Diag(VarLoc, diag::note_declare_parameter_strong);
}
}
@@ -14272,7 +14695,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
if (HasBlocksAttr || CaptureType->isReferenceType() ||
- (S.getLangOpts().OpenMP && S.IsOpenMPCapturedDecl(Var))) {
+ (S.getLangOpts().OpenMP && S.isOpenMPCapturedDecl(Var))) {
// Block capture by reference does not change the capture or
// declaration reference types.
ByRef = true;
@@ -14332,7 +14755,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
}
-/// \brief Capture the given variable in the captured region.
+/// Capture the given variable in the captured region.
static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
VarDecl *Var,
SourceLocation Loc,
@@ -14345,14 +14768,14 @@ 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);
+ ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel);
}
if (ByRef)
@@ -14392,7 +14815,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
return true;
}
-/// \brief Create a field within the lambda class for the variable
+/// Create a field within the lambda class for the variable
/// being captured.
static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI,
QualType FieldType, QualType DeclRefType,
@@ -14410,7 +14833,7 @@ static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI,
Lambda->addDecl(Field);
}
-/// \brief Capture the given variable in the lambda.
+/// Capture the given variable in the lambda.
static bool captureInLambda(LambdaScopeInfo *LSI,
VarDecl *Var,
SourceLocation Loc,
@@ -14544,7 +14967,7 @@ bool Sema::tryCaptureVariable(
// Capture global variables if it is required to use private copy of this
// variable.
bool IsGlobal = !Var->hasLocalStorage();
- if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var)))
+ if (IsGlobal && !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var)))
return true;
Var = Var->getCanonicalDecl();
@@ -14909,7 +15332,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// A reference initialized by a constant expression can never be
// odr-used, so simply ignore it.
if (!Var->getType()->isReferenceType() ||
- (SemaRef.LangOpts.OpenMP && SemaRef.IsOpenMPCapturedDecl(Var)))
+ (SemaRef.LangOpts.OpenMP && SemaRef.isOpenMPCapturedDecl(Var)))
SemaRef.MaybeODRUseExprs.insert(E);
} else if (OdrUseContext) {
MarkVarDeclODRUsed(Var, Loc, SemaRef,
@@ -14925,7 +15348,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (RefersToEnclosingScope) {
LambdaScopeInfo *const LSI =
SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
- if (LSI && !LSI->CallOperator->Encloses(Var->getDeclContext())) {
+ 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
@@ -14943,7 +15367,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
-/// \brief Mark a variable referenced, and check whether it is odr-used
+/// 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.
void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
@@ -14984,7 +15408,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
}
-/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
+/// Perform reference-marking and odr-use handling for a DeclRefExpr.
void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
// TODO: update this with DR# once a defect report is filed.
// C++11 defect. The address of a pure member should not be an ODR use, even
@@ -14997,7 +15421,7 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
-/// \brief Perform reference-marking and odr-use handling for a MemberExpr.
+/// Perform reference-marking and odr-use handling for a MemberExpr.
void Sema::MarkMemberReferenced(MemberExpr *E) {
// C++11 [basic.def.odr]p2:
// A non-overloaded function whose name appears as a potentially-evaluated
@@ -15016,7 +15440,7 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse);
}
-/// \brief Perform marking for a reference to an arbitrary declaration. It
+/// Perform marking for a reference to an arbitrary declaration. It
/// marks the declaration referenced, and performs odr-use checking for
/// functions and variables. This method should not be used when building a
/// normal expression which refers to a variable.
@@ -15079,7 +15503,7 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) {
}
namespace {
- /// \brief Helper class that marks all of the declarations referenced by
+ /// Helper class that marks all of the declarations referenced by
/// potentially-evaluated subexpressions as "referenced".
class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> {
Sema &S;
@@ -15152,7 +15576,7 @@ namespace {
};
}
-/// \brief Mark any declarations that appear within this expression or any
+/// Mark any declarations that appear within this expression or any
/// potentially-evaluated subexpressions as "referenced".
///
/// \param SkipLocalVariables If true, don't mark local variables as
@@ -15162,7 +15586,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E);
}
-/// \brief Emit a diagnostic that describes an effect on the run-time behavior
+/// Emit a diagnostic that describes an effect on the run-time behavior
/// of the program being compiled.
///
/// This routine emits the given diagnostic when the code currently being
@@ -15228,7 +15652,8 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
// If we're inside a decltype's expression, don't check for a valid return
// type or construct temporaries until we know whether this is the last call.
- if (ExprEvalContexts.back().IsDecltype) {
+ if (ExprEvalContexts.back().ExprContext ==
+ ExpressionEvaluationContextRecord::EK_Decltype) {
ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE);
return false;
}
@@ -15319,7 +15744,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
<< FixItHint::CreateReplacement(Loc, "==");
}
-/// \brief Redundant parentheses over an equality comparison can indicate
+/// Redundant parentheses over an equality comparison can indicate
/// that the user intended an assignment used as condition.
void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
// Don't warn if the parens came from a macro.