summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Sema/SemaExpr.cpp')
-rw-r--r--gnu/llvm/tools/clang/lib/Sema/SemaExpr.cpp1587
1 files changed, 1005 insertions, 582 deletions
diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaExpr.cpp
index a6e43765e10..3dc6fb151cb 100644
--- a/gnu/llvm/tools/clang/lib/Sema/SemaExpr.cpp
+++ b/gnu/llvm/tools/clang/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.
@@ -246,7 +248,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
Diag(Loc, diag::err_deleted_inherited_ctor_use)
<< Ctor->getParent()
<< Ctor->getInheritedConstructor().getConstructor()->getParent();
- else
+ else
Diag(Loc, diag::err_deleted_function_use);
NoteDeletedFunction(FD);
return true;
@@ -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) {
@@ -399,7 +401,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
if (MissingNilLoc.isInvalid())
Diag(Loc, diag::warn_missing_sentinel) << int(calleeType);
else
- Diag(MissingNilLoc, diag::warn_missing_sentinel)
+ Diag(MissingNilLoc, diag::warn_missing_sentinel)
<< int(calleeType)
<< FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue);
Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType);
@@ -421,7 +423,7 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
if (result.isInvalid()) return ExprError();
E = result.get();
}
-
+
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
@@ -477,12 +479,12 @@ static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
const ObjCIvarDecl *IV = OIRE->getDecl();
if (!IV)
return;
-
+
DeclarationName MemberName = IV->getDeclName();
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
if (!Member || !Member->isStr("isa"))
return;
-
+
const Expr *Base = OIRE->getBase();
QualType BaseType = Base->getType();
if (OIRE->isArrow())
@@ -534,7 +536,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (result.isInvalid()) return ExprError();
E = result.get();
}
-
+
// C++ [conv.lval]p1:
// A glvalue of a non-function, non-array type T can be
// converted to a prvalue.
@@ -602,8 +604,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
(void)isCompleteType(E->getExprLoc(), T);
UpdateMarkingForLValueToRValue(E);
-
- // Loading a __weak object implicitly retains the value, so we need a cleanup to
+
+ // Loading a __weak object implicitly retains the value, so we need a cleanup to
// balance that.
if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
Cleanup.setExprNeedsCleanups(true);
@@ -612,14 +614,14 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
nullptr, VK_RValue);
// C11 6.3.2.1p2:
- // ... if the lvalue has atomic type, the value has the non-atomic version
+ // ... if the lvalue has atomic type, the value has the non-atomic version
// of the type of the lvalue ...
if (const AtomicType *Atomic = T->getAs<AtomicType>()) {
T = Atomic->getValueType().getUnqualifiedType();
Res = ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic, Res.get(),
nullptr, VK_RValue);
}
-
+
return Res;
}
@@ -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)
@@ -868,7 +876,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
E = ExprRes.get();
}
}
-
+
ExprResult ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
@@ -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,
@@ -1003,7 +1011,7 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
CK_IntegralToFloating);
return FloatTy;
}
-
+
// Convert both sides to the appropriate complex float.
assert(IntTy->isComplexIntegerType());
QualType result = S.Context.getComplexType(FloatTy);
@@ -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,
@@ -1194,7 +1201,7 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
QualType ComplexType = S.Context.getComplexType(ScalarType);
RHS = S.ImpCastExprToType(RHS.get(), ComplexType,
CK_IntegralRealToComplex);
-
+
return ComplexType;
}
@@ -1205,7 +1212,7 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
handleIntegerConversion<doIntegralCast, doComplexIntegralCast>
(S, LHS, RHS, LHSType, RHSEltType, IsCompAssign);
QualType ComplexType = S.Context.getComplexType(ScalarType);
-
+
if (!IsCompAssign)
LHS = S.ImpCastExprToType(LHS.get(), ComplexType,
CK_IntegralRealToComplex);
@@ -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))
@@ -2074,16 +2080,17 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
(Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam)
? LookupObjCImplicitSelfParam
: LookupOrdinaryName);
- if (TemplateArgs) {
+ 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,
@@ -2092,7 +2099,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
- // If the result might be in a dependent base class, this is a dependent
+ // If the result might be in a dependent base class, this is a dependent
// id-expression.
if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
@@ -2149,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)) {
@@ -2347,7 +2357,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo *II, bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
ObjCMethodDecl *CurMethod = getCurMethodDecl();
-
+
// Check for error condition which is already reported.
if (!CurMethod)
return ExprError();
@@ -2426,15 +2436,16 @@ 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())
Diag(Loc, diag::warn_implicitly_retains_self)
<< FixItHint::CreateInsertion(Loc, "self->");
}
-
+
return Result;
}
} else if (CurMethod->isInstanceMethod()) {
@@ -2471,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:
///
@@ -2717,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);
@@ -2730,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();
@@ -2753,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,
@@ -2769,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();
}
@@ -2898,7 +2918,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
if (!CapturedType.isNull())
type = CapturedType;
}
-
+
break;
}
@@ -2914,7 +2934,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
diagnoseUncapturableValueReference(*this, Loc, BD, CurContext);
break;
}
-
+
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
@@ -2939,7 +2959,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
valueKind = VK_LValue;
break;
}
-
+
// C99 DR 316 says that, if a function type comes from a
// function definition (without a prototype), that type is only
// used for checking compatibility. Therefore, when referencing
@@ -3034,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);
@@ -3044,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,
@@ -3064,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;
}
@@ -3086,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())
@@ -3281,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);
@@ -3314,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"))
@@ -3554,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) {
@@ -3572,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
@@ -3656,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
@@ -3910,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,
@@ -3954,17 +4023,17 @@ 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,
UnaryExprOrTypeTrait ExprKind) {
ExprResult PE = CheckPlaceholderExpr(E);
- if (PE.isInvalid())
+ if (PE.isInvalid())
return ExprError();
E = PE.get();
-
+
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
@@ -4072,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,
@@ -4328,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>()) {
@@ -4392,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
@@ -4478,7 +4562,7 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
diag::note_default_argument_declared_here);
return true;
}
-
+
if (Param->hasUninstantiatedDefaultArg()) {
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
@@ -4580,7 +4664,7 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
"default argument expression has capturing blocks?");
}
- // We already type-checked the argument, so we know it works.
+ // We already type-checked the argument, so we know it works.
// Just mark all of the declarations in this potentially-evaluated expression
// as being "referenced".
MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
@@ -4777,7 +4861,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
Diag(FDecl->getLocStart(), diag::note_callee_decl)
<< FDecl;
-
+
// This deletes the extra arguments.
Call->setNumArgs(Context, NumParams);
return true;
@@ -4785,7 +4869,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
}
SmallVector<Expr *, 8> AllArgs;
VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
-
+
Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
Proto, 0, Args, AllArgs, CallType);
if (Invalid)
@@ -4831,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)
@@ -5187,11 +5275,11 @@ tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
// Check if the naming class in which the unresolved members were found is
// related (same as or is a base of) to the enclosing class.
-
+
if (!enclosingClassIsRelatedToClassInWhichMembersWereFound(UME, S))
return;
-
-
+
+
DeclContext *EnclosingFunctionCtx = S.CurContext->getParent()->getParent();
// If the enclosing function is not dependent, then this lambda is
// capture ready, so if we can capture this, do so.
@@ -5496,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())
@@ -5506,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());
}
}
@@ -5537,7 +5625,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
<< (Args.size() > Def->param_size()) << FDecl << Fn->getSourceRange();
}
-
+
// If the function we're calling isn't a function prototype, but we have
// a function prototype from a prior declaratiom, use that prototype.
if (!FDecl->hasPrototype())
@@ -5555,7 +5643,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (ArgE.isInvalid())
return true;
-
+
Arg = ArgE.getAs<Expr>();
} else {
@@ -5566,7 +5654,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
Arg = ArgE.getAs<Expr>();
}
-
+
if (RequireCompleteType(Arg->getLocStart(),
Arg->getType(),
diag::err_call_incomplete_argument, Arg))
@@ -5640,7 +5728,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
InitializedEntity Entity
= InitializedEntity::InitializeCompoundLiteralInit(TInfo);
InitializationKind Kind
- = InitializationKind::CreateCStyleCast(LParenLoc,
+ = InitializationKind::CreateCStyleCast(LParenLoc,
SourceRange(LParenLoc, RParenLoc),
/*InitList=*/true);
InitializationSequence InitSeq(*this, Entity, Kind, LiteralExpr);
@@ -5705,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);
@@ -5919,11 +6007,11 @@ static bool breakDownVectorType(QualType type, uint64_t &len,
assert(eltType->isScalarType());
return true;
}
-
+
// We allow lax conversion to and from non-vector types, but only if
// they're real types (i.e. non-complex, non-pointer scalar types).
if (!type->isRealType()) return false;
-
+
len = 1;
eltType = type;
return true;
@@ -5938,7 +6026,7 @@ static bool breakDownVectorType(QualType type, uint64_t &len,
/// vector nor a real type.
bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) {
assert(destTy->isVectorType() || srcTy->isVectorType());
-
+
// Disallow lax conversions between scalars and ExtVectors (these
// conversions are allowed for other vector types because common headers
// depend on them). Most scalar OP ExtVector cases are handled by the
@@ -5951,13 +6039,13 @@ bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) {
QualType srcEltTy, destEltTy;
if (!breakDownVectorType(srcTy, srcLen, srcEltTy)) return false;
if (!breakDownVectorType(destTy, destLen, destEltTy)) return false;
-
+
// ASTContext::getTypeSize will return the size rounded up to a
// power of 2, so instead of using that, we need to use the raw
// element size multiplied by the element count.
uint64_t srcEltSize = Context.getTypeSize(srcEltTy);
uint64_t destEltSize = Context.getTypeSize(destEltTy);
-
+
return (srcLen * srcEltSize == destLen * destEltSize);
}
@@ -5965,7 +6053,7 @@ bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) {
/// known to be a vector type?
bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) {
assert(destTy->isVectorType() || srcTy->isVectorType());
-
+
if (!Context.getLangOpts().LaxVectorConversions)
return false;
return areLaxCompatibleVectorTypes(srcTy, destTy);
@@ -6123,9 +6211,9 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
if (getLangOpts().CPlusPlus && !castType->isVoidType() &&
!getSourceManager().isInSystemMacro(LParenLoc))
Diag(LParenLoc, diag::warn_old_style_cast) << CastExpr->getSourceRange();
-
+
CheckTollFreeBridgeCast(castType, CastExpr);
-
+
CheckObjCBridgeRelatedCast(castType, CastExpr);
DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr);
@@ -6162,7 +6250,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
SmallVector<Expr *, 8> initExprs;
const VectorType *VTy = Ty->getAs<VectorType>();
unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
-
+
// '(...)' form of vector initialization in AltiVec: the number of
// initializers must be one or must match the size of the vector.
// If a single value is specified in the initializer then it will be
@@ -6202,7 +6290,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
PrepareScalarCast(Literal, ElemTy));
return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get());
}
-
+
initExprs.append(exprs, exprs + numExprs);
}
// FIXME: This means that pretty-printing the final AST will produce curly
@@ -6239,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,
@@ -6280,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();
@@ -6299,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();
@@ -6316,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) {
@@ -6329,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,
@@ -6463,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,
@@ -6488,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,
@@ -6527,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,
@@ -6547,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.
@@ -6602,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
@@ -6647,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
@@ -6662,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
@@ -6692,14 +6780,14 @@ 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
OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond,
ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
- Cond = S.DefaultFunctionArrayLvalueConversion(Cond.get());
+ Cond = S.DefaultFunctionArrayLvalueConversion(Cond.get());
if (Cond.isInvalid())
return QualType();
QualType CondTy = Cond.get()->getType();
@@ -6727,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();
@@ -7050,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)) {
@@ -7097,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;
}
@@ -7265,7 +7359,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
ExprResult Cond = CondExpr, LHS = LHSExpr, RHS = RHSExpr;
- QualType result = CheckConditionalOperands(Cond, LHS, RHS,
+ QualType result = CheckConditionalOperands(Cond, LHS, RHS,
VK, OK, QuestionLoc);
if (result.isNull() || Cond.isInvalid() || LHS.isInvalid() ||
RHS.isInvalid())
@@ -7337,7 +7431,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
// Treat lifetime mismatches as fatal.
else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
-
+
// For GCC/MS compatibility, other qualifier mismatches are treated
// as still compatible in C.
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
@@ -7684,7 +7778,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// - conversions from 'Class' to the redefinition type
if (RHSType->isObjCClassType() &&
- Context.hasSameType(LHSType,
+ Context.hasSameType(LHSType,
Context.getObjCClassRedefinitionType())) {
Kind = CK_BitCast;
return Compatible;
@@ -7751,10 +7845,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// A* -> B*
if (RHSType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
- Sema::AssignConvertType result =
+ Sema::AssignConvertType result =
checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
- result == Compatible &&
+ result == Compatible &&
!CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType))
result = IncompatibleObjCWeakRef;
return result;
@@ -7778,7 +7872,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// - conversions to 'Class' from its redefinition type
if (LHSType->isObjCClassType() &&
- Context.hasSameType(RHSType,
+ Context.hasSameType(RHSType,
Context.getObjCClassRedefinitionType())) {
return Compatible;
}
@@ -7787,7 +7881,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
}
// Only under strict condition T^ is compatible with an Objective-C pointer.
- if (RHSType->isBlockPointerType() &&
+ if (RHSType->isBlockPointerType() &&
LHSType->isBlockCompatibleObjCPointerType(Context)) {
if (ConvertRHS)
maybeExtendBlockObject(RHS);
@@ -7848,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,
@@ -8015,11 +8109,11 @@ 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;
}
}
-
+
CastKind Kind;
Sema::AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
@@ -8054,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();
}
@@ -8116,7 +8249,7 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
// The conversion to apply to the scalar before splatting it,
// if necessary.
CastKind scalarCast = CK_NoOp;
-
+
if (vectorEltTy->isIntegralType(S.Context)) {
if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() ||
(scalarTy->isIntegerType() &&
@@ -8216,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;
@@ -8576,7 +8709,7 @@ QualType Sema::CheckRemainderOperands(
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
- if (LHS.get()->getType()->hasIntegerRepresentation() &&
+ if (LHS.get()->getType()->hasIntegerRepresentation() &&
RHS.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
/*AllowBothBool*/getLangOpts().AltiVec,
@@ -8594,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
@@ -8604,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
@@ -8613,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.
@@ -8628,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());
@@ -8644,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());
@@ -8656,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,
@@ -8672,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
@@ -8703,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
@@ -8805,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;
@@ -8856,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());
@@ -8928,7 +9061,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
// In C++ adding zero to a null pointer is defined.
llvm::APSInt KnownVal;
if (!getLangOpts().CPlusPlus ||
- (!IExp->isValueDependent() &&
+ (!IExp->isValueDependent() &&
(!IExp->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) {
// Check the conditions to see if this is the 'p = nullptr + n' idiom.
bool IsGNUIdiom = BinaryOperator::isNullPointerArithmeticExtension(
@@ -9005,7 +9138,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
Expr::NPC_ValueDependentIsNotNull)) {
// In C++ adding zero to a null pointer is defined.
llvm::APSInt KnownVal;
- if (!getLangOpts().CPlusPlus ||
+ if (!getLangOpts().CPlusPlus ||
(!RHS.get()->isValueDependent() &&
(!RHS.get()->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) {
diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false);
@@ -9154,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) {
@@ -9300,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) {
@@ -9339,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) {
@@ -9349,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) {
@@ -9587,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;
+ }
- if (isa<CastExpr>(LHSStripped))
- LHSStripped = LHSStripped->IgnoreParenCasts();
- if (isa<CastExpr>(RHSStripped))
- RHSStripped = RHSStripped->IgnoreParenCasts();
+ // 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();
- // 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;
- }
+ assert(!Type.isNull() && "composite type for <=> has not been set");
- if (literalString) {
- DiagRuntimeBehavior(Loc, nullptr,
- PDiag(diag::warn_stringcompare)
- << isa<ObjCEncodeExpr>(literalStringStripped)
- << literalString->getSourceRange());
+ 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");
+ }();
+
+ 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());
+
+ checkEnumComparison(S, Loc, LHS.get(), RHS.get());
- LHSType = LHS.get()->getType();
- RHSType = RHS.get()->getType();
+ 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 =
@@ -9725,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)
@@ -9752,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
@@ -9825,7 +10218,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
else
RHS = ImpCastExprToType(RHS.get(), LHSType, Kind);
}
- return ResultTy;
+ return computeResultTy();
}
if (getLangOpts().CPlusPlus) {
@@ -9835,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();
}
}
@@ -9848,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 &&
@@ -9876,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();
}
}
}
@@ -9889,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.
@@ -9913,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.
@@ -9937,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() ||
@@ -9970,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()) {
@@ -9984,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()) ||
@@ -10017,37 +10416,37 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (isError)
return QualType();
}
-
+
if (LHSType->isIntegerType())
LHS = ImpCastExprToType(LHS.get(), RHSType,
LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
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();
}
}
@@ -10101,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,
@@ -10121,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());
}
@@ -10207,7 +10596,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
// Check vector operands differently.
if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
-
+
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
@@ -10418,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;
}
@@ -10660,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
@@ -10701,7 +11120,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
<< LHSType.getUnqualifiedType();
return QualType();
}
-
+
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
Expr *RHSCheck = RHS.get();
@@ -10938,7 +11357,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// Otherwise, we just need a complete type.
if (checkArithmeticIncompletePointerType(S, OpLoc, Op) ||
checkArithmeticOnObjCPointer(S, OpLoc, Op))
- return QualType();
+ return QualType();
} else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
S.Diag(OpLoc, diag::ext_integer_increment_complex)
@@ -10978,7 +11397,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return ResType.getUnqualifiedType();
}
}
-
+
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
/// This routine allows us to typecheck complex/recursive expressions
@@ -11046,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,
@@ -11138,7 +11557,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
Expr::LValueClassification lval = op->ClassifyLValue(Context);
unsigned AddressOfError = AO_No_Error;
- if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) {
+ if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) {
bool sfinae = (bool)isSFINAEContext();
Diag(OpLoc, isSFINAEContext() ? diag::err_typecheck_addrof_temporary
: diag::ext_typecheck_addrof_temporary)
@@ -11353,7 +11772,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
// ...except that certain expressions are never l-values in C.
if (!S.getLangOpts().CPlusPlus && Result.isCForbiddenLValueType())
VK = VK_RValue;
-
+
return Result;
}
@@ -11419,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();
@@ -11447,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
@@ -11489,7 +11910,7 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R,
if (SelArg0.startswith("performSelector"))
Diag = diag::warn_objc_pointer_masking_performSelector;
}
-
+
S.Diag(OpLoc, Diag)
<< ObjCPointerExpr->getSourceRange();
}
@@ -11584,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);
@@ -11642,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());
@@ -11678,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);
@@ -11740,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);
@@ -11790,7 +12209,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
else if (const ObjCIvarRefExpr *OIRE =
dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts()))
DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
-
+
// Opc is not a compound assignment if CompResultTy is null.
if (CompResultTy.isNull()) {
if (ConvertHalfVec)
@@ -11858,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
@@ -11873,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;
@@ -11881,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;
@@ -11889,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)) {
@@ -11911,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)) {
@@ -11926,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,
@@ -12039,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
@@ -12115,7 +12549,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
return ExprError();
}
}
-
+
ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
if (LHS.isInvalid()) return ExprError();
LHSExpr = LHS.get();
@@ -12161,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) {
@@ -12168,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();
@@ -12193,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);
@@ -12206,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
@@ -12242,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.
@@ -12312,7 +12762,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
-
+
// LNot always has type int. C99 6.5.3.3p5.
// In C++, it's bool. C++ 5.3.1p8
resultType = Context.getLogicalOperationType();
@@ -12338,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 "
@@ -12356,37 +12806,37 @@ 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;
-
+
ValueDecl *VD = DRE->getDecl();
if (!VD->isCXXClassMember())
return false;
-
+
if (isa<FieldDecl>(VD) || isa<IndirectFieldDecl>(VD))
return true;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(VD))
return Method->isInstance();
-
+
return false;
}
-
+
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
if (!ULE->getQualifier())
return false;
-
+
for (NamedDecl *D : ULE->decls()) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isInstance())
@@ -12396,10 +12846,10 @@ static bool isQualifiedMemberAccess(Expr *E) {
break;
}
}
-
+
return false;
}
-
+
return false;
}
@@ -12549,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())
@@ -12584,17 +13031,17 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
QualType ArgTy = TInfo->getType();
bool Dependent = ArgTy->isDependentType();
SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange();
-
+
// We must have at least one component that refers to the type, and the first
// one is known to be a field designator. Verify that the ArgTy represents
// a struct/union/class.
if (!Dependent && !ArgTy->isRecordType())
- return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type)
+ return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type)
<< ArgTy << TypeRange);
-
+
// Type must be complete per C99 7.17p3 because a declaring a variable
// with an incomplete type would be ill-formed.
- if (!Dependent
+ if (!Dependent
&& RequireCompleteType(BuiltinLoc, ArgTy,
diag::err_offsetof_incomplete_type, TypeRange))
return ExprError();
@@ -12614,7 +13061,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
CurrentType = AT->getElementType();
} else
CurrentType = Context.DependentTy;
-
+
ExprResult IdxRval = DefaultLvalueConversion(static_cast<Expr*>(OC.U.E));
if (IdxRval.isInvalid())
return ExprError();
@@ -12633,7 +13080,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
Exprs.push_back(Idx);
continue;
}
-
+
// Offset of a field.
if (CurrentType->isDependentType()) {
// We have the offset of a field, but we can't look into the dependent
@@ -12642,19 +13089,19 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
CurrentType = Context.DependentTy;
continue;
}
-
+
// We need to have a complete type to look into.
if (RequireCompleteType(OC.LocStart, CurrentType,
diag::err_offsetof_incomplete_type))
return ExprError();
-
+
// Look for the designated field.
const RecordType *RC = CurrentType->getAs<RecordType>();
- if (!RC)
+ if (!RC)
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
<< CurrentType);
RecordDecl *RD = RC->getDecl();
-
+
// C++ [lib.support.types]p5:
// The macro offsetof accepts a restricted set of type arguments in this
// International Standard. type shall be a POD structure or a POD union
@@ -12675,7 +13122,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
<< CurrentType))
DidWarnAboutNonPOD = true;
}
-
+
// Look for the field.
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
LookupQualifiedName(R, RD);
@@ -12688,9 +13135,9 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
if (!MemberDecl)
return ExprError(Diag(BuiltinLoc, diag::err_no_member)
- << OC.U.IdentInfo << RD << SourceRange(OC.LocStart,
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart,
OC.LocEnd));
-
+
// C99 7.17p3:
// (If the specified member is a bit-field, the behavior is undefined.)
//
@@ -12733,9 +13180,9 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
} else
Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd));
- CurrentType = MemberDecl->getType().getNonReferenceType();
+ CurrentType = MemberDecl->getType().getNonReferenceType();
}
-
+
return OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, TInfo,
Comps, Exprs, RParenLoc);
}
@@ -12746,7 +13193,7 @@ ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
ParsedType ParsedArgTy,
ArrayRef<OffsetOfComponent> Components,
SourceLocation RParenLoc) {
-
+
TypeSourceInfo *ArgTInfo;
QualType ArgTy = GetTypeFromParser(ParsedArgTy, &ArgTInfo);
if (ArgTy.isNull())
@@ -12784,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();
@@ -12851,7 +13298,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
T = Context.getFunctionType(Context.DependentTy, None, EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
-
+
// GetTypeForDeclarator always produces a function type for a block
// literal signature. Furthermore, it is always a FunctionProtoType
// unless the function was written with a typedef.
@@ -12929,7 +13376,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
CheckParmsForFunctionDef(CurBlock->TheDecl->parameters(),
/*CheckParameterNames=*/false);
}
-
+
// Finally we can process decl attributes.
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
@@ -12990,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(),
@@ -13005,7 +13452,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionType::ExtInfo Ext = FTy->getExtInfo();
if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true);
-
+
// Turn protoless block types into nullary block types.
if (isa<FunctionNoProtoType>(FTy)) {
FunctionProtoType::ExtProtoInfo EPI;
@@ -13053,7 +13500,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (getLangOpts().CPlusPlus && RetTy->isRecordType() &&
!BSI->TheDecl->isDependentContext())
computeNRVO(Body, BSI);
-
+
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
@@ -13070,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;
}
}
@@ -13227,7 +13674,7 @@ bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
if (!ID || !ID->getIdentifier()->isStr("NSString"))
return false;
}
-
+
// Ignore any parens, implicit casts (should only be
// array-to-pointer decays), and not-so-opaque values. The last is
// important for making this trigger for property assignments.
@@ -13336,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;
@@ -13460,8 +13906,8 @@ 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,
FirstType, /*TakingAddress=*/true);
@@ -13471,7 +13917,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (Action == AA_Returning && ConvTy == IncompatiblePointer)
EmitRelatedResultTypeNoteForReturn(DstType);
-
+
if (Complained)
*Complained = true;
return isInvalid;
@@ -13485,7 +13931,7 @@ ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
S.Diag(Loc, diag::err_expr_not_ice) << S.LangOpts.CPlusPlus << SR;
}
} Diagnoser;
-
+
return VerifyIntegerConstantExpression(E, Result, Diagnoser);
}
@@ -13495,16 +13941,16 @@ ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
bool AllowFold) {
class IDDiagnoser : public VerifyICEDiagnoser {
unsigned DiagID;
-
+
public:
IDDiagnoser(unsigned DiagID)
: VerifyICEDiagnoser(DiagID == 0), DiagID(DiagID) { }
-
+
void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override {
S.Diag(Loc, DiagID) << SR;
}
} Diagnoser(DiagID);
-
+
return VerifyIntegerConstantExpression(E, Result, Diagnoser, AllowFold);
}
@@ -13701,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() {
@@ -13724,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.
@@ -13806,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;
@@ -13856,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) {
@@ -14070,26 +14516,26 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
// capture.
}
-
-static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
+
+static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
bool &SubCapturesAreNested,
- QualType &CaptureType,
+ QualType &CaptureType,
QualType &DeclRefType) {
// Check whether we've already captured it.
if (CSI->CaptureMap.count(Var)) {
// If we found a capture, any subcaptures are nested.
SubCapturesAreNested = true;
-
+
// Retrieve the capture type for this variable.
CaptureType = CSI->getCapture(Var).getCaptureType();
-
+
// Compute the type of an expression that refers to this variable.
DeclRefType = CaptureType.getNonReferenceType();
// 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) &&
@@ -14102,8 +14548,8 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
-static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
- SourceLocation Loc,
+static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
+ SourceLocation Loc,
const bool Diagnose, Sema &S) {
if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
return getLambdaAwareParentOfDeclContext(DC);
@@ -14114,11 +14560,11 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *
return nullptr;
}
-// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
+// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
// certain types of variables (unnamed, variably modified types etc.)
// so check for eligibility.
-static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
- SourceLocation Loc,
+static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
+ SourceLocation Loc,
const bool Diagnose, Sema &S) {
bool IsBlock = isa<BlockScopeInfo>(CSI);
@@ -14140,7 +14586,7 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
if (Var->getType()->isVariablyModifiedType() && IsBlock) {
if (Diagnose) {
S.Diag(Loc, diag::err_ref_vm_type);
- S.Diag(Var->getLocation(), diag::note_previous_decl)
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
}
return false;
@@ -14185,21 +14631,21 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
}
// Returns true if the capture by block was successful.
-static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
- SourceLocation Loc,
- const bool BuildAndDiagnose,
+static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
+ SourceLocation Loc,
+ const bool BuildAndDiagnose,
QualType &CaptureType,
- QualType &DeclRefType,
+ QualType &DeclRefType,
const bool Nested,
Sema &S) {
Expr *CopyExpr = nullptr;
bool ByRef = false;
-
+
// Blocks are not allowed to capture arrays.
if (CaptureType->isArrayType()) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_ref_array_type);
- S.Diag(Var->getLocation(), diag::note_previous_decl)
+ S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
}
return false;
@@ -14242,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);
}
}
@@ -14273,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;
@@ -14281,7 +14703,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Block capture by copy introduces 'const'.
CaptureType = CaptureType.getNonReferenceType().withConst();
DeclRefType = CaptureType;
-
+
if (S.getLangOpts().CPlusPlus && BuildAndDiagnose) {
if (const RecordType *Record = DeclRefType->getAs<RecordType>()) {
// The capture logic needs the destructor, so make sure we mark it.
@@ -14301,15 +14723,15 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// the stack requires a const copy constructor. This is not true
// of the copy/move done to move a __block variable to the heap.
Expr *DeclRef = new (S.Context) DeclRefExpr(Var, Nested,
- DeclRefType.withConst(),
+ DeclRefType.withConst(),
VK_LValue, Loc);
-
+
ExprResult Result
= S.PerformCopyInitialization(
InitializedEntity::InitializeBlock(Var->getLocation(),
CaptureType, false),
Loc, DeclRef);
-
+
// Build a full-expression copy expression if initialization
// succeeded and used a non-trivial constructor. Recover from
// errors by pretending that the copy isn't necessary.
@@ -14325,7 +14747,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Actually capture the variable.
if (BuildAndDiagnose)
- BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
+ BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
SourceLocation(), CaptureType, CopyExpr);
return true;
@@ -14333,27 +14755,27 @@ 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,
- const bool BuildAndDiagnose,
+ VarDecl *Var,
+ SourceLocation Loc,
+ const bool BuildAndDiagnose,
QualType &CaptureType,
- QualType &DeclRefType,
+ QualType &DeclRefType,
const bool RefersToCapturedVariable,
Sema &S) {
// By default, capture variables by reference.
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)
@@ -14377,7 +14799,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
RD->addDecl(Field);
if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
S.setOpenMPCaptureKind(Field, Var, RSI->OpenMPLevel);
-
+
CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
DeclRefType, VK_LValue, Loc);
Var->setReferenced(true);
@@ -14388,14 +14810,14 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
if (BuildAndDiagnose)
RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc,
SourceLocation(), CaptureType, CopyExpr);
-
-
+
+
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,
+static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI,
QualType FieldType, QualType DeclRefType,
SourceLocation Loc,
bool RefersToCapturedVariable) {
@@ -14411,15 +14833,15 @@ 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,
- const bool BuildAndDiagnose,
+ VarDecl *Var,
+ SourceLocation Loc,
+ const bool BuildAndDiagnose,
QualType &CaptureType,
- QualType &DeclRefType,
+ QualType &DeclRefType,
const bool RefersToCapturedVariable,
- const Sema::TryCaptureKind Kind,
+ const Sema::TryCaptureKind Kind,
SourceLocation EllipsisLoc,
const bool IsTopScope,
Sema &S) {
@@ -14431,7 +14853,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
} else {
ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
}
-
+
// Compute the type of the field that will capture this variable.
if (ByRef) {
// C++11 [expr.prim.lambda]p15:
@@ -14443,7 +14865,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
//
// FIXME: It is not clear whether we want to build an lvalue reference
// to the DeclRefType or to CaptureType.getNonReferenceType(). GCC appears
- // to do the former, while EDG does the latter. Core issue 1249 will
+ // to do the former, while EDG does the latter. Core issue 1249 will
// clarify, but for now we follow GCC because it's a more permissive and
// easily defensible position.
CaptureType = S.Context.getLValueReferenceType(DeclRefType);
@@ -14491,26 +14913,26 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
if (BuildAndDiagnose)
addAsFieldToClosureType(S, LSI, CaptureType, DeclRefType, Loc,
RefersToCapturedVariable);
-
+
// Compute the type of a reference to this captured variable.
if (ByRef)
DeclRefType = CaptureType.getNonReferenceType();
else {
// C++ [expr.prim.lambda]p5:
- // The closure type for a lambda-expression has a public inline
- // function call operator [...]. This function call operator is
- // declared const (9.3.1) if and only if the lambda-expression's
+ // The closure type for a lambda-expression has a public inline
+ // function call operator [...]. This function call operator is
+ // declared const (9.3.1) if and only if the lambda-expression's
// parameter-declaration-clause is not followed by mutable.
DeclRefType = CaptureType.getNonReferenceType();
if (!LSI->Mutable && !CaptureType->isReferenceType())
- DeclRefType.addConst();
+ DeclRefType.addConst();
}
-
+
// Add the capture.
if (BuildAndDiagnose)
- LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
+ LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr);
-
+
return true;
}
@@ -14523,10 +14945,10 @@ bool Sema::tryCaptureVariable(
DeclContext *VarDC = Var->getDeclContext();
if (Var->isInitCapture())
VarDC = VarDC->getParent();
-
+
DeclContext *DC = CurContext;
- const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
- ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
+ const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
+ ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
// We need to sync up the Declaration Context with the
// FunctionScopeIndexToStopAt
if (FunctionScopeIndexToStopAt) {
@@ -14537,7 +14959,7 @@ bool Sema::tryCaptureVariable(
}
}
-
+
// If the variable is declared in the current context, there is no need to
// capture it.
if (VarDC == DC) return true;
@@ -14545,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();
@@ -14553,7 +14975,7 @@ bool Sema::tryCaptureVariable(
// performing the "simple" checks that don't depend on type. We stop when
// we've either hit the declared scope of the variable or find an existing
// capture of that variable. We start from the innermost capturing-entity
- // (the DC) and ensure that all intervening capturing-entities
+ // (the DC) and ensure that all intervening capturing-entities
// (blocks/lambdas etc.) between the innermost capturer and the variable`s
// declcontext can either capture the variable or have already captured
// the variable.
@@ -14565,8 +14987,8 @@ bool Sema::tryCaptureVariable(
do {
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
- DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var,
- ExprLoc,
+ DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var,
+ ExprLoc,
BuildAndDiagnose,
*this);
// We need to check for the parent *first* because, if we *have*
@@ -14585,29 +15007,29 @@ bool Sema::tryCaptureVariable(
// Check whether we've already captured it.
- if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
+ if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
DeclRefType)) {
CSI->getCapture(Var).markUsed(BuildAndDiagnose);
break;
}
- // If we are instantiating a generic lambda call operator body,
+ // If we are instantiating a generic lambda call operator body,
// we do not want to capture new variables. What was captured
// during either a lambdas transformation or initial parsing
- // should be used.
+ // should be used.
if (isGenericLambdaCallOperatorSpecialization(DC)) {
if (BuildAndDiagnose) {
- LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
- Diag(Var->getLocation(), diag::note_previous_decl)
+ Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
- Diag(LSI->Lambda->getLocStart(), diag::note_lambda_decl);
+ Diag(LSI->Lambda->getLocStart(), diag::note_lambda_decl);
} else
diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
}
return true;
}
- // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
+ // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
// certain types of variables (unnamed, variably modified types etc.)
// so check for eligibility.
if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this))
@@ -14648,11 +15070,11 @@ bool Sema::tryCaptureVariable(
}
}
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
- // No capture-default, and this is not an explicit capture
- // so cannot capture this variable.
+ // No capture-default, and this is not an explicit capture
+ // so cannot capture this variable.
if (BuildAndDiagnose) {
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
- Diag(Var->getLocation(), diag::note_previous_decl)
+ Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
if (cast<LambdaScopeInfo>(CSI)->Lambda)
Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
@@ -14661,12 +15083,12 @@ bool Sema::tryCaptureVariable(
// capture a variable that an inner lambda explicitly captures, we
// should have the inner lambda do the explicit capture - because
// it makes for cleaner diagnostics later. This would purely be done
- // so that the diagnostic does not misleadingly claim that a variable
- // can not be captured by a lambda implicitly even though it is captured
+ // so that the diagnostic does not misleadingly claim that a variable
+ // can not be captured by a lambda implicitly even though it is captured
// explicitly. Suggestion:
- // - create const bool VariableCaptureWasInitiallyExplicit = Explicit
+ // - create const bool VariableCaptureWasInitiallyExplicit = Explicit
// at the function head
- // - cache the StartingDeclContext - this must be a lambda
+ // - cache the StartingDeclContext - this must be a lambda
// - captureInLambda in the innermost lambda the variable.
}
return true;
@@ -14678,31 +15100,31 @@ bool Sema::tryCaptureVariable(
} while (!VarDC->Equals(DC));
// Walk back down the scope stack, (e.g. from outer lambda to inner lambda)
- // computing the type of the capture at each step, checking type-specific
- // requirements, and adding captures if requested.
- // If the variable had already been captured previously, we start capturing
- // at the lambda nested within that one.
- for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N;
+ // computing the type of the capture at each step, checking type-specific
+ // requirements, and adding captures if requested.
+ // If the variable had already been captured previously, we start capturing
+ // at the lambda nested within that one.
+ for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N;
++I) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
-
+
if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(CSI)) {
- if (!captureInBlock(BSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
+ if (!captureInBlock(BSI, Var, ExprLoc,
+ BuildAndDiagnose, CaptureType,
DeclRefType, Nested, *this))
return true;
Nested = true;
} else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- if (!captureInCapturedRegion(RSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
+ if (!captureInCapturedRegion(RSI, Var, ExprLoc,
+ BuildAndDiagnose, CaptureType,
DeclRefType, Nested, *this))
return true;
Nested = true;
} else {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
- if (!captureInLambda(LSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
- DeclRefType, Nested, Kind, EllipsisLoc,
+ if (!captureInLambda(LSI, Var, ExprLoc,
+ BuildAndDiagnose, CaptureType,
+ DeclRefType, Nested, Kind, EllipsisLoc,
/*IsTopScope*/I == N - 1, *this))
return true;
Nested = true;
@@ -14712,7 +15134,7 @@ bool Sema::tryCaptureVariable(
}
bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
- TryCaptureKind Kind, SourceLocation EllipsisLoc) {
+ TryCaptureKind Kind, SourceLocation EllipsisLoc) {
QualType CaptureType;
QualType DeclRefType;
return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc,
@@ -14731,10 +15153,10 @@ bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
QualType CaptureType;
QualType DeclRefType;
-
+
// Determine whether we can capture this variable.
if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
- /*BuildAndDiagnose=*/false, CaptureType,
+ /*BuildAndDiagnose=*/false, CaptureType,
DeclRefType, nullptr))
return QualType();
@@ -14743,49 +15165,49 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
-// If either the type of the variable or the initializer is dependent,
+// If either the type of the variable or the initializer is dependent,
// return false. Otherwise, determine whether the variable is a constant
// expression. Use this if you need to know if a variable that might or
// might not be dependent is truly a constant expression.
-static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
+static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
ASTContext &Context) {
-
- if (Var->getType()->isDependentType())
+
+ if (Var->getType()->isDependentType())
return false;
const VarDecl *DefVD = nullptr;
Var->getAnyInitializer(DefVD);
- if (!DefVD)
+ if (!DefVD)
return false;
EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
Expr *Init = cast<Expr>(Eval->Value);
- if (Init->isValueDependent())
+ if (Init->isValueDependent())
return false;
- return IsVariableAConstantExpression(Var, Context);
+ return IsVariableAConstantExpression(Var, Context);
}
void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
- // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
+ // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
// an object that satisfies the requirements for appearing in a
// constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
// is immediately applied." This function handles the lvalue-to-rvalue
// conversion part.
MaybeODRUseExprs.erase(E->IgnoreParens());
-
+
// If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
// to a variable that is a constant expression, and if so, identify it as
- // a reference to a variable that does not involve an odr-use of that
- // variable.
+ // a reference to a variable that does not involve an odr-use of that
+ // variable.
if (LambdaScopeInfo *LSI = getCurLambda()) {
Expr *SansParensExpr = E->IgnoreParens();
VarDecl *Var = nullptr;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
Var = dyn_cast<VarDecl>(ME->getMemberDecl());
-
- if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
- LSI->markVariableExprAsNonODRUsed(SansParensExpr);
+
+ if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
+ LSI->markVariableExprAsNonODRUsed(SansParensExpr);
}
}
@@ -14910,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,
@@ -14945,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) {
@@ -14986,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
@@ -14999,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
@@ -15018,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.
@@ -15081,18 +15503,18 @@ 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;
bool SkipLocalVariables;
-
+
public:
typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited;
-
- EvaluatedExprMarker(Sema &S, bool SkipLocalVariables)
+
+ EvaluatedExprMarker(Sema &S, bool SkipLocalVariables)
: Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { }
-
+
void VisitDeclRefExpr(DeclRefExpr *E) {
// If we were asked not to visit local variables, don't.
if (SkipLocalVariables) {
@@ -15100,7 +15522,7 @@ namespace {
if (VD->hasLocalStorage())
return;
}
-
+
S.MarkDeclRefReferenced(E);
}
@@ -15108,13 +15530,13 @@ namespace {
S.MarkMemberReferenced(E);
Inherited::VisitMemberExpr(E);
}
-
+
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
S.MarkFunctionReferenced(E->getLocStart(),
const_cast<CXXDestructorDecl*>(E->getTemporary()->getDestructor()));
Visit(E->getSubExpr());
}
-
+
void VisitCXXNewExpr(CXXNewExpr *E) {
if (E->getOperatorNew())
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorNew());
@@ -15129,18 +15551,18 @@ namespace {
QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType());
if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
- S.MarkFunctionReferenced(E->getLocStart(),
+ S.MarkFunctionReferenced(E->getLocStart(),
S.LookupDestructor(Record));
}
-
+
Inherited::VisitCXXDeleteExpr(E);
}
-
+
void VisitCXXConstructExpr(CXXConstructExpr *E) {
S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
Inherited::VisitCXXConstructExpr(E);
}
-
+
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Visit(E->getExpr());
}
@@ -15154,17 +15576,17 @@ 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
+/// \param SkipLocalVariables If true, don't mark local variables as
/// 'referenced'.
-void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
+void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
bool SkipLocalVariables) {
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
@@ -15230,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;
}
@@ -15238,7 +15661,7 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
class CallReturnIncompleteDiagnoser : public TypeDiagnoser {
FunctionDecl *FD;
CallExpr *CE;
-
+
public:
CallReturnIncompleteDiagnoser(FunctionDecl *FD, CallExpr *CE)
: FD(FD), CE(CE) { }
@@ -15249,14 +15672,14 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
<< T << CE->getSourceRange();
return;
}
-
+
S.Diag(Loc, diag::err_call_function_incomplete_return)
<< CE->getSourceRange() << FD->getDeclName() << T;
S.Diag(FD->getLocation(), diag::note_entity_declared_at)
<< FD->getDeclName();
}
} Diagnoser(FD, CE);
-
+
if (RequireCompleteType(Loc, ReturnType, Diagnoser))
return true;
@@ -15321,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.
@@ -15339,7 +15762,7 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
opE->getLHS()->IgnoreParenImpCasts()->isModifiableLvalue(Context)
== Expr::MLV_Valid) {
SourceLocation Loc = opE->getOperatorLoc();
-
+
Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange();
SourceRange ParenERange = ParenE->getSourceRange();
Diag(Loc, diag::note_equality_comparison_silence)
@@ -15676,7 +16099,7 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
}
// Rebuild the appropriate pointer-to-function type.
- switch (Kind) {
+ switch (Kind) {
case FK_MemberFunction:
// Nothing to do.
break;
@@ -15725,15 +16148,15 @@ ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) {
if (E->getCastKind() == CK_FunctionToPointerDecay) {
assert(E->getValueKind() == VK_RValue);
assert(E->getObjectKind() == OK_Ordinary);
-
+
E->setType(DestType);
-
+
// Rebuild the sub-expression as the pointee (function) type.
DestType = DestType->castAs<PointerType>()->getPointeeType();
-
+
ExprResult Result = Visit(E->getSubExpr());
if (!Result.isUsable()) return ExprError();
-
+
E->setSubExpr(Result.get());
return E;
} else if (E->getCastKind() == CK_LValueToRValue) {
@@ -15795,7 +16218,7 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
SC_None, false/*isInlineSpecified*/,
FD->hasPrototype(),
false/*isConstexprSpecified*/);
-
+
if (FD->getQualifier())
NewFD->setQualifierInfo(FD->getQualifierLoc());
@@ -16063,7 +16486,7 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
Sema::LookupOrdinaryName);
if (LookupName(Result, getCurScope()) && Result.isSingleResult()) {
NamedDecl *ND = Result.getFoundDecl();
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
Context.setBOOLDecl(TD);
}
}