summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp991
1 files changed, 700 insertions, 291 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d8869ffe945a2..e41cd5b6653a2 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1990,16 +1990,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.clear();
}
- // In Microsoft mode, if we are performing lookup from within a friend
- // function definition declared at class scope then we must set
- // DC to the lexical parent to be able to search into the parent
- // class.
- if (getLangOpts().MSVCCompat && isa<FunctionDecl>(DC) &&
- cast<FunctionDecl>(DC)->getFriendObjectKind() &&
- DC->getLexicalParent()->isRecord())
- DC = DC->getLexicalParent();
- else
- DC = DC->getParent();
+ DC = DC->getLookupParent();
}
// We didn't find anything, so try to correct for a typo.
@@ -2491,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
}
-/// LookupInObjCMethod - The parser has read a name in, and Sema has
-/// detected that we're currently inside an ObjC method. Perform some
-/// additional lookup.
+/// The parser has read a name in, and Sema has detected that we're currently
+/// inside an ObjC method. Perform some additional checks and determine if we
+/// should form a reference to an ivar.
///
/// Ideally, most of this would be done by lookup, but there's
/// actually quite a lot of extra work involved.
-///
-/// Returns a null sentinel to indicate trivial success.
-ExprResult
-Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II, bool AllowBuiltinCreation) {
+DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II) {
SourceLocation Loc = Lookup.getNameLoc();
ObjCMethodDecl *CurMethod = getCurMethodDecl();
// Check for error condition which is already reported.
if (!CurMethod)
- return ExprError();
+ return DeclResult(true);
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -2535,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarDecl *IV = nullptr;
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
// Diagnose using an ivar in a class method.
- if (IsClassMethod)
- return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
- << IV->getDeclName());
-
- // If we're referencing an invalid decl, just return this as a silent
- // error node. The error diagnostic was already emitted on the decl.
- if (IV->isInvalidDecl())
- return ExprError();
-
- // Check if referencing a field with __attribute__((deprecated)).
- if (DiagnoseUseOfDecl(IV, Loc))
- return ExprError();
+ if (IsClassMethod) {
+ Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
+ return DeclResult(true);
+ }
// Diagnose the use of an ivar outside of the declaring class.
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
@@ -2554,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
!getLangOpts().DebuggerSupport)
Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName();
- // FIXME: This should use a new expr for a direct reference, don't
- // turn this into Self->ivar, just return a BareIVarExpr or something.
- IdentifierInfo &II = Context.Idents.get("self");
- UnqualifiedId SelfName;
- SelfName.setIdentifier(&II, SourceLocation());
- SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
- CXXScopeSpec SelfScopeSpec;
- SourceLocation TemplateKWLoc;
- ExprResult SelfExpr =
- ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
- /*HasTrailingLParen=*/false,
- /*IsAddressOfOperand=*/false);
- if (SelfExpr.isInvalid())
- return ExprError();
-
- SelfExpr = DefaultLvalueConversion(SelfExpr.get());
- if (SelfExpr.isInvalid())
- return ExprError();
-
- MarkAnyDeclReferenced(Loc, IV, true);
-
- ObjCMethodFamily MF = CurMethod->getMethodFamily();
- if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
- !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
- Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
-
- ObjCIvarRefExpr *Result = new (Context)
- ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
- IV->getLocation(), SelfExpr.get(), true, true);
-
- if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (!isUnevaluatedContext() &&
- !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
- getCurFunction()->recordUseOfWeak(Result);
- }
- if (getLangOpts().ObjCAutoRefCount)
- if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
- ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
-
- return Result;
+ // Success.
+ return IV;
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -2608,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
} else if (Lookup.isSingleResult() &&
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
// If accessing a stand-alone ivar in a class method, this is an error.
- if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl()))
- return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
- << IV->getDeclName());
- }
-
- if (Lookup.empty() && II && AllowBuiltinCreation) {
- // FIXME. Consolidate this with similar code in LookupName.
- if (unsigned BuiltinID = II->getBuiltinID()) {
- if (!(getLangOpts().CPlusPlus &&
- Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
- NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, Lookup.isForRedeclaration(),
- Lookup.getNameLoc());
- if (D) Lookup.addDecl(D);
- }
+ if (const ObjCIvarDecl *IV =
+ dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) {
+ Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
+ return DeclResult(true);
}
}
+
+ // Didn't encounter an error, didn't find an ivar.
+ return DeclResult(false);
+}
+
+ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc,
+ ObjCIvarDecl *IV) {
+ ObjCMethodDecl *CurMethod = getCurMethodDecl();
+ assert(CurMethod && CurMethod->isInstanceMethod() &&
+ "should not reference ivar from this context");
+
+ ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
+ assert(IFace && "should not reference ivar from this context");
+
+ // If we're referencing an invalid decl, just return this as a silent
+ // error node. The error diagnostic was already emitted on the decl.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check if referencing a field with __attribute__((deprecated)).
+ if (DiagnoseUseOfDecl(IV, Loc))
+ return ExprError();
+
+ // FIXME: This should use a new expr for a direct reference, don't
+ // turn this into Self->ivar, just return a BareIVarExpr or something.
+ IdentifierInfo &II = Context.Idents.get("self");
+ UnqualifiedId SelfName;
+ SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
+ CXXScopeSpec SelfScopeSpec;
+ SourceLocation TemplateKWLoc;
+ ExprResult SelfExpr =
+ ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
+ /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
+ if (SelfExpr.isInvalid())
+ return ExprError();
+
+ SelfExpr = DefaultLvalueConversion(SelfExpr.get());
+ if (SelfExpr.isInvalid())
+ return ExprError();
+
+ MarkAnyDeclReferenced(Loc, IV, true);
+
+ ObjCMethodFamily MF = CurMethod->getMethodFamily();
+ if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
+ Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
+
+ ObjCIvarRefExpr *Result = new (Context)
+ ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
+ IV->getLocation(), SelfExpr.get(), true, true);
+
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ if (!isUnevaluatedContext() &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ if (getLangOpts().ObjCAutoRefCount)
+ if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
+ ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
+
+ return Result;
+}
+
+/// The parser has read a name in, and Sema has detected that we're currently
+/// inside an ObjC method. Perform some additional checks and determine if we
+/// should form a reference to an ivar. If so, build an expression referencing
+/// that ivar.
+ExprResult
+Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II, bool AllowBuiltinCreation) {
+ // FIXME: Integrate this lookup step into LookupParsedName.
+ DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II);
+ if (Ivar.isInvalid())
+ return ExprError();
+ if (Ivar.isUsable())
+ return BuildIvarRefExpr(S, Lookup.getNameLoc(),
+ cast<ObjCIvarDecl>(Ivar.get()));
+
+ if (Lookup.empty() && II && AllowBuiltinCreation)
+ LookupBuiltin(Lookup);
+
// Sentinel value saying that we didn't do anything special.
- return ExprResult((Expr *)nullptr);
+ return ExprResult(false);
}
/// Cast a base object to a member's actual type.
@@ -3216,13 +3230,15 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
SmallString<32> RawChars;
ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(),
Str, RawChars);
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
+ ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide,
/*Pascal*/ false, ResTy, Loc);
} else {
ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst());
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
+ ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
/*Pascal*/ false, ResTy, Loc);
@@ -3462,7 +3478,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
Context.adjustStringLiteralBaseType(Context.CharTy.withConst()),
- llvm::APInt(32, Length + 1), ArrayType::Normal, 0);
+ llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
/*Pascal*/false, StrTy, &TokLoc, 1);
@@ -3808,6 +3824,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
QualType ExprTy = E->getType();
assert(!ExprTy->isReferenceType());
+ bool IsUnevaluatedOperand =
+ (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
+ ExprKind == UETT_PreferredAlignOf);
+ if (IsUnevaluatedOperand) {
+ ExprResult Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return true;
+ E = Result.get();
+ }
+
if (ExprKind == UETT_VecStep)
return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange());
@@ -3845,9 +3871,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
// The operand for sizeof and alignof is in an unevaluated expression context,
// so side effects could result in unintended consequences.
- if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
- ExprKind == UETT_PreferredAlignOf) &&
- !inTemplateInstantiation() && E->HasSideEffects(Context, false))
+ if (IsUnevaluatedOperand && !inTemplateInstantiation() &&
+ E->HasSideEffects(Context, false))
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
@@ -3946,8 +3971,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
}
static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
- E = E->IgnoreParens();
-
// Cannot know anything else if the expression is dependent.
if (E->isTypeDependent())
return false;
@@ -3959,9 +3982,10 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
}
ValueDecl *D = nullptr;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ Expr *Inner = E->IgnoreParens();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Inner)) {
D = DRE->getDecl();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Inner)) {
D = ME->getMemberDecl();
}
@@ -4026,7 +4050,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
T = QualType();
break;
// These types are never variably-modified.
@@ -4317,6 +4341,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
base = result.get();
}
+ // A comma-expression as the index is deprecated in C++2a onwards.
+ if (getLangOpts().CPlusPlus2a &&
+ ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
+ (isa<CXXOperatorCallExpr>(idx) &&
+ cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) {
+ Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ }
+
// Handle any non-overload placeholder types in the base and index
// expressions. We can't handle overloads here because the other
// operand might be an overloadable type, in which case the overload
@@ -4823,8 +4856,10 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
LocalInstantiationScope Local(*this);
- Result = SubstInitializer(UninstExpr, MutiLevelArgList,
- /*DirectInit*/false);
+ runWithSufficientStackSpace(CallLoc, [&] {
+ Result = SubstInitializer(UninstExpr, MutiLevelArgList,
+ /*DirectInit*/false);
+ });
}
if (Result.isInvalid())
return true;
@@ -4935,7 +4970,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FunctionCallCCC>(*this);
+ return std::make_unique<FunctionCallCCC>(*this);
}
private:
@@ -5296,6 +5331,11 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // In practice we'll never use this, since all SVE types are sugared
+ // via TypedefTypes rather than exposed directly as BuiltinTypes.
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define PLACEHOLDER_TYPE(ID, SINGLETON_ID)
#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID:
#include "clang/AST/BuiltinTypes.def"
@@ -5366,8 +5406,8 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
QualType DeclType = FDecl->getType();
const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(DeclType);
- if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) ||
- !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams())
+ if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || !FT ||
+ ArgExprs.size() < FT->getNumParams())
return nullptr;
bool NeedsNewDecl = false;
@@ -5406,6 +5446,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
return nullptr;
FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = FT->isVariadic();
QualType OverloadTy = Context.getFunctionType(FT->getReturnType(),
OverloadParams, EPI);
DeclContext *Parent = FDecl->getParent();
@@ -5883,7 +5924,9 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
<< FDecl << Fn->getSourceRange());
// CUDA: Kernel function must have 'void' return type
- if (!FuncT->getReturnType()->isVoidType())
+ if (!FuncT->getReturnType()->isVoidType() &&
+ !FuncT->getReturnType()->getAs<AutoType>() &&
+ !FuncT->getReturnType()->isInstantiationDependentType())
return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return)
<< Fn->getType() << Fn->getSourceRange());
} else {
@@ -6103,6 +6146,77 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ExprResult
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
+ // Only produce each kind of designated initialization diagnostic once.
+ SourceLocation FirstDesignator;
+ bool DiagnosedArrayDesignator = false;
+ bool DiagnosedNestedDesignator = false;
+ bool DiagnosedMixedDesignator = false;
+
+ // Check that any designated initializers are syntactically valid in the
+ // current language mode.
+ for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
+ if (auto *DIE = dyn_cast<DesignatedInitExpr>(InitArgList[I])) {
+ if (FirstDesignator.isInvalid())
+ FirstDesignator = DIE->getBeginLoc();
+
+ if (!getLangOpts().CPlusPlus)
+ break;
+
+ if (!DiagnosedNestedDesignator && DIE->size() > 1) {
+ DiagnosedNestedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_nested)
+ << DIE->getDesignatorsSourceRange();
+ }
+
+ for (auto &Desig : DIE->designators()) {
+ if (!Desig.isFieldDesignator() && !DiagnosedArrayDesignator) {
+ DiagnosedArrayDesignator = true;
+ Diag(Desig.getBeginLoc(), diag::ext_designated_init_array)
+ << Desig.getSourceRange();
+ }
+ }
+
+ if (!DiagnosedMixedDesignator &&
+ !isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[0]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[0]->getSourceRange();
+ }
+ } else if (getLangOpts().CPlusPlus && !DiagnosedMixedDesignator &&
+ isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ auto *DIE = cast<DesignatedInitExpr>(InitArgList[0]);
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[I]->getSourceRange();
+ }
+ }
+
+ if (FirstDesignator.isValid()) {
+ // Only diagnose designated initiaization as a C++20 extension if we didn't
+ // already diagnose use of (non-C++20) C99 designator syntax.
+ if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator &&
+ !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) {
+ Diag(FirstDesignator, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_designated_init
+ : diag::ext_cxx_designated_init);
+ } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) {
+ Diag(FirstDesignator, diag::ext_designated_init);
+ }
+ }
+
+ return BuildInitList(LBraceLoc, InitArgList, RBraceLoc);
+}
+
+ExprResult
+Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
+ SourceLocation RBraceLoc) {
+ // Semantic analysis for initializers is done by ActOnDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being initialized.
+
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
@@ -6117,9 +6231,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
}
}
- // Semantic analysis for initializers is done by ActOnDeclarator() and
- // CheckInitializer() - it requires knowledge of the object being initialized.
-
InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
@@ -6422,8 +6533,28 @@ bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) {
bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) {
assert(destTy->isVectorType() || srcTy->isVectorType());
- if (!Context.getLangOpts().LaxVectorConversions)
+ switch (Context.getLangOpts().getLaxVectorConversions()) {
+ case LangOptions::LaxVectorConversionKind::None:
return false;
+
+ case LangOptions::LaxVectorConversionKind::Integer:
+ if (!srcTy->isIntegralOrEnumerationType()) {
+ auto *Vec = srcTy->getAs<VectorType>();
+ if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType())
+ return false;
+ }
+ if (!destTy->isIntegralOrEnumerationType()) {
+ auto *Vec = destTy->getAs<VectorType>();
+ if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType())
+ return false;
+ }
+ // OK, integer (vector) -> integer (vector) bitcast.
+ break;
+
+ case LangOptions::LaxVectorConversionKind::All:
+ break;
+ }
+
return areLaxCompatibleVectorTypes(srcTy, destTy);
}
@@ -6616,8 +6747,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
assert(Ty->isVectorType() && "Expected vector type");
SmallVector<Expr *, 8> initExprs;
- const VectorType *VTy = Ty->getAs<VectorType>();
- unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+ const VectorType *VTy = Ty->castAs<VectorType>();
+ unsigned numElems = VTy->getNumElements();
// '(...)' form of vector initialization in AltiVec: the number of
// initializers must be one or must match the size of the vector.
@@ -6628,7 +6759,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
// vector. If a single value is specified in the initializer then it will
// be replicated to all the components of the vector
if (numExprs == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = VTy->getElementType();
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
@@ -6650,7 +6781,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
if (getLangOpts().OpenCL &&
VTy->getVectorKind() == VectorType::GenericVector &&
numExprs == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = VTy->getElementType();
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
@@ -6949,8 +7080,8 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
QualType RHSTy = RHS.get()->getType();
// get the "pointed to" types
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
@@ -7400,9 +7531,10 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
} else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
- } else if ((LHSTy->isObjCQualifiedIdType() ||
- RHSTy->isObjCQualifiedIdType()) &&
- Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ } else if ((LHSOPT->isObjCQualifiedIdType() ||
+ RHSOPT->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT,
+ true)) {
// Need to handle "id<xx>" explicitly.
// GCC allows qualified id and any Objective-C type to devolve to
// id. Currently localizing to here until clear this should be
@@ -7434,8 +7566,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
LHS = RHS = true;
return QualType();
}
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<ObjCObjectPointerType>()->getPointeeType();
QualType destPointee
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
@@ -7454,8 +7586,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
LHS = RHS = true;
return QualType();
}
- QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
QualType destPointee
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
@@ -7488,7 +7620,12 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
return BinaryOperator::isAdditiveOp(Opc) ||
BinaryOperator::isMultiplicativeOp(Opc) ||
- BinaryOperator::isShiftOp(Opc);
+ BinaryOperator::isShiftOp(Opc) || Opc == BO_And || Opc == BO_Or;
+ // This only checks for bitwise-or and bitwise-and, but not bitwise-xor and
+ // not any of the logical operators. Bitwise-xor is commonly used as a
+ // logical-xor because there is no logical-xor operator. The logical
+ // operators, including uses of xor, have a high false positive rate for
+ // precedence warnings.
}
/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
@@ -7578,7 +7715,11 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
// The condition is an arithmetic binary expression, with a right-
// hand side that looks boolean, so warn.
- Self.Diag(OpLoc, diag::warn_precedence_conditional)
+ unsigned DiagID = BinaryOperator::isBitwiseOp(CondOpcode)
+ ? diag::warn_precedence_bitwise_conditional
+ : diag::warn_precedence_conditional;
+
+ Self.Diag(OpLoc, DiagID)
<< Condition->getSourceRange()
<< BinaryOperator::getOpcodeStr(CondOpcode);
@@ -7960,8 +8101,8 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
return Sema::IncompatiblePointer;
return Sema::Compatible;
}
- QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
// make an exception for id<P>
@@ -9063,7 +9204,7 @@ static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
-static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
+static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS,
SourceLocation Loc) {
const auto *LUE = dyn_cast<UnaryExprOrTypeTraitExpr>(LHS);
const auto *RUE = dyn_cast<UnaryExprOrTypeTraitExpr>(RHS);
@@ -9073,7 +9214,8 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
RUE->getKind() != UETT_SizeOf)
return;
- QualType LHSTy = LUE->getArgumentExpr()->IgnoreParens()->getType();
+ const Expr *LHSArg = LUE->getArgumentExpr()->IgnoreParens();
+ QualType LHSTy = LHSArg->getType();
QualType RHSTy;
if (RUE->isArgumentType())
@@ -9081,12 +9223,33 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
else
RHSTy = RUE->getArgumentExpr()->IgnoreParens()->getType();
- if (!LHSTy->isPointerType() || RHSTy->isPointerType())
- return;
- if (LHSTy->getPointeeType() != RHSTy)
- return;
+ if (LHSTy->isPointerType() && !RHSTy->isPointerType()) {
+ if (!S.Context.hasSameUnqualifiedType(LHSTy->getPointeeType(), RHSTy))
+ return;
- S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange();
+ S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) {
+ if (const ValueDecl *LHSArgDecl = DRE->getDecl())
+ S.Diag(LHSArgDecl->getLocation(), diag::note_pointer_declared_here)
+ << LHSArgDecl;
+ }
+ } else if (const auto *ArrayTy = S.Context.getAsArrayType(LHSTy)) {
+ QualType ArrayElemTy = ArrayTy->getElementType();
+ if (ArrayElemTy != S.Context.getBaseElementType(ArrayTy) ||
+ ArrayElemTy->isDependentType() || RHSTy->isDependentType() ||
+ ArrayElemTy->isCharType() ||
+ S.Context.getTypeSize(ArrayElemTy) == S.Context.getTypeSize(RHSTy))
+ return;
+ S.Diag(Loc, diag::warn_division_sizeof_array)
+ << LHSArg->getSourceRange() << ArrayElemTy << RHSTy;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) {
+ if (const ValueDecl *LHSArgDecl = DRE->getDecl())
+ S.Diag(LHSArgDecl->getLocation(), diag::note_array_declared_here)
+ << LHSArgDecl;
+ }
+
+ S.Diag(Loc, diag::note_precedence_silence) << RHS;
+ }
}
static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
@@ -9122,7 +9285,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
if (IsDiv) {
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv);
- DiagnoseDivisionSizeofPointer(*this, LHS.get(), RHS.get(), Loc);
+ DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc);
}
return compType;
}
@@ -9281,8 +9444,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
// if both are pointers check if operation is valid wrt address spaces
if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) {
- const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>();
- const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>();
+ const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>();
+ const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>();
if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
S.Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
@@ -9914,8 +10077,8 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
QualType T = S.FindCompositePointerType(Loc, LHS, RHS);
if (T.isNull()) {
- if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) &&
- (RHSType->isPointerType() || RHSType->isMemberPointerType()))
+ if ((LHSType->isAnyPointerType() || LHSType->isMemberPointerType()) &&
+ (RHSType->isAnyPointerType() || RHSType->isMemberPointerType()))
diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
else
S.InvalidOperands(Loc, LHS, RHS);
@@ -10129,20 +10292,18 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS,
<< FixItHint::CreateInsertion(SecondClose, ")");
}
-// 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))
- return DR->getDecl();
- if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) {
- if (Ivar->isFreeIvar())
- return Ivar->getDecl();
- }
- if (MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
+// Returns true if E refers to a non-weak array.
+static bool checkForArray(const Expr *E) {
+ const ValueDecl *D = nullptr;
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ D = DR->getDecl();
+ } else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
if (Mem->isImplicitAccess())
- return Mem->getMemberDecl();
+ D = Mem->getMemberDecl();
}
- return nullptr;
+ if (!D)
+ return false;
+ return D->getType()->isArrayType() && !D->isWeak();
}
/// Diagnose some forms of syntactically-obvious tautological comparison.
@@ -10175,47 +10336,54 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
// 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;
+
+ // Used for indexing into %select in warn_comparison_always
+ enum {
+ AlwaysConstant,
+ AlwaysTrue,
+ AlwaysFalse,
+ AlwaysEqual, // std::strong_ordering::equal from operator<=>
+ };
+
+ if (Expr::isSameComparisonOperand(LHS, RHS)) {
+ unsigned Result;
switch (Opc) {
case BO_EQ: case BO_LE: case BO_GE:
- Result = "true";
+ Result = AlwaysTrue;
break;
case BO_NE: case BO_LT: case BO_GT:
- Result = "false";
+ Result = AlwaysFalse;
break;
case BO_Cmp:
- Result = "'std::strong_ordering::equal'";
+ Result = AlwaysEqual;
break;
default:
+ Result = AlwaysConstant;
break;
}
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
- << 0 /*self-comparison*/ << !Result.empty()
+ << 0 /*self-comparison*/
<< Result);
- } else if (DL && DR &&
- DL->getType()->isArrayType() && DR->getType()->isArrayType() &&
- !DL->isWeak() && !DR->isWeak()) {
+ } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
// What is it always going to evaluate to?
- StringRef Result;
+ unsigned Result;
switch(Opc) {
case BO_EQ: // e.g. array1 == array2
- Result = "false";
+ Result = AlwaysFalse;
break;
case BO_NE: // e.g. array1 != array2
- Result = "true";
+ Result = AlwaysTrue;
break;
default: // e.g. array1 <= array2
// The best we can say is 'a constant'
+ Result = AlwaysConstant;
break;
}
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
<< 1 /*array comparison*/
- << !Result.empty() << Result);
+ << Result);
}
if (isa<CastExpr>(LHSStripped))
@@ -10370,7 +10538,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
return QualType();
}
QualType IntType =
- LHSStrippedType->getAs<EnumType>()->getDecl()->getIntegerType();
+ LHSStrippedType->castAs<EnumType>()->getDecl()->getIntegerType();
assert(IntType->isArithmeticType());
// We can't use `CK_IntegralCast` when the underlying type is 'bool', so we
@@ -10446,6 +10614,32 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
return S.Context.getLogicalOperationType();
}
+void Sema::CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE) {
+ if (!NullE.get()->getType()->isAnyPointerType())
+ return;
+ int NullValue = PP.isMacroDefined("NULL") ? 0 : 1;
+ if (!E.get()->getType()->isAnyPointerType() &&
+ E.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull) ==
+ Expr::NPCK_ZeroExpression) {
+ if (const auto *CL = dyn_cast<CharacterLiteral>(E.get())) {
+ if (CL->getValue() == 0)
+ Diag(E.get()->getExprLoc(), diag::warn_pointer_compare)
+ << NullValue
+ << FixItHint::CreateReplacement(E.get()->getExprLoc(),
+ NullValue ? "NULL" : "(void *)0");
+ } else if (const auto *CE = dyn_cast<CStyleCastExpr>(E.get())) {
+ TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
+ QualType T = Context.getCanonicalType(TI->getType()).getUnqualifiedType();
+ if (T == Context.CharTy)
+ Diag(E.get()->getExprLoc(), diag::warn_pointer_compare)
+ << NullValue
+ << FixItHint::CreateReplacement(E.get()->getExprLoc(),
+ NullValue ? "NULL" : "(void *)0");
+ }
+ }
+}
+
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
@@ -10479,6 +10673,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/true);
+ if (!getLangOpts().CPlusPlus && BinaryOperator::isEqualityOp(Opc)) {
+ CheckPtrComparisonWithNullChar(LHS, RHS);
+ CheckPtrComparisonWithNullChar(RHS, LHS);
+ }
// Handle vector comparisons separately.
if (LHS.get()->getType()->isVectorType() ||
@@ -10623,8 +10821,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LCanPointeeTy != RCanPointeeTy) {
// Treat NULL constant as a special case in OpenCL.
if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
- const PointerType *LHSPtr = LHSType->getAs<PointerType>();
- if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) {
+ const PointerType *LHSPtr = LHSType->castAs<PointerType>();
+ if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) {
Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSType << RHSType << 0 /* comparison */
@@ -10889,7 +11087,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// the largest type to the smallest type to avoid cases where long long == long,
// where long gets picked over long long.
QualType Sema::GetSignedVectorType(QualType V) {
- const VectorType *VTy = V->getAs<VectorType>();
+ const VectorType *VTy = V->castAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (isa<ExtVectorType>(VTy)) {
@@ -10944,7 +11142,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
if (getLangOpts().AltiVec &&
- vType->getAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
+ vType->castAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
return Context.getLogicalOperationType();
// For non-floating point types, check for self-comparisons of the form
@@ -10963,6 +11161,120 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
return GetSignedVectorType(vType);
}
+static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
+ const ExprResult &XorRHS,
+ const SourceLocation Loc) {
+ // Do not diagnose macros.
+ if (Loc.isMacroID())
+ return;
+
+ bool Negative = false;
+ bool ExplicitPlus = false;
+ const auto *LHSInt = dyn_cast<IntegerLiteral>(XorLHS.get());
+ const auto *RHSInt = dyn_cast<IntegerLiteral>(XorRHS.get());
+
+ if (!LHSInt)
+ return;
+ if (!RHSInt) {
+ // Check negative literals.
+ if (const auto *UO = dyn_cast<UnaryOperator>(XorRHS.get())) {
+ UnaryOperatorKind Opc = UO->getOpcode();
+ if (Opc != UO_Minus && Opc != UO_Plus)
+ return;
+ RHSInt = dyn_cast<IntegerLiteral>(UO->getSubExpr());
+ if (!RHSInt)
+ return;
+ Negative = (Opc == UO_Minus);
+ ExplicitPlus = !Negative;
+ } else {
+ return;
+ }
+ }
+
+ const llvm::APInt &LeftSideValue = LHSInt->getValue();
+ llvm::APInt RightSideValue = RHSInt->getValue();
+ if (LeftSideValue != 2 && LeftSideValue != 10)
+ return;
+
+ if (LeftSideValue.getBitWidth() != RightSideValue.getBitWidth())
+ return;
+
+ CharSourceRange ExprRange = CharSourceRange::getCharRange(
+ LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation()));
+ llvm::StringRef ExprStr =
+ Lexer::getSourceText(ExprRange, S.getSourceManager(), S.getLangOpts());
+
+ CharSourceRange XorRange =
+ CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
+ llvm::StringRef XorStr =
+ Lexer::getSourceText(XorRange, S.getSourceManager(), S.getLangOpts());
+ // Do not diagnose if xor keyword/macro is used.
+ if (XorStr == "xor")
+ return;
+
+ std::string LHSStr = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(LHSInt->getSourceRange()),
+ S.getSourceManager(), S.getLangOpts());
+ std::string RHSStr = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(RHSInt->getSourceRange()),
+ S.getSourceManager(), S.getLangOpts());
+
+ if (Negative) {
+ RightSideValue = -RightSideValue;
+ RHSStr = "-" + RHSStr;
+ } else if (ExplicitPlus) {
+ RHSStr = "+" + RHSStr;
+ }
+
+ StringRef LHSStrRef = LHSStr;
+ StringRef RHSStrRef = RHSStr;
+ // Do not diagnose literals with digit separators, binary, hexadecimal, octal
+ // literals.
+ if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") ||
+ RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") ||
+ LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") ||
+ RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") ||
+ (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) ||
+ (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) ||
+ LHSStrRef.find('\'') != StringRef::npos ||
+ RHSStrRef.find('\'') != StringRef::npos)
+ return;
+
+ bool SuggestXor = S.getLangOpts().CPlusPlus || S.getPreprocessor().isMacroDefined("xor");
+ const llvm::APInt XorValue = LeftSideValue ^ RightSideValue;
+ int64_t RightSideIntValue = RightSideValue.getSExtValue();
+ if (LeftSideValue == 2 && RightSideIntValue >= 0) {
+ std::string SuggestedExpr = "1 << " + RHSStr;
+ bool Overflow = false;
+ llvm::APInt One = (LeftSideValue - 1);
+ llvm::APInt PowValue = One.sshl_ov(RightSideValue, Overflow);
+ if (Overflow) {
+ if (RightSideIntValue < 64)
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base)
+ << ExprStr << XorValue.toString(10, true) << ("1LL << " + RHSStr)
+ << FixItHint::CreateReplacement(ExprRange, "1LL << " + RHSStr);
+ else if (RightSideIntValue == 64)
+ S.Diag(Loc, diag::warn_xor_used_as_pow) << ExprStr << XorValue.toString(10, true);
+ else
+ return;
+ } else {
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base_extra)
+ << ExprStr << XorValue.toString(10, true) << SuggestedExpr
+ << PowValue.toString(10, true)
+ << FixItHint::CreateReplacement(
+ ExprRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr);
+ }
+
+ S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0x2 ^ " + RHSStr) << SuggestXor;
+ } else if (LeftSideValue == 10) {
+ std::string SuggestedValue = "1e" + std::to_string(RightSideIntValue);
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base)
+ << ExprStr << XorValue.toString(10, true) << SuggestedValue
+ << FixItHint::CreateReplacement(ExprRange, SuggestedValue);
+ S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0xA ^ " + RHSStr) << SuggestXor;
+ }
+}
+
QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
// Ensure that either both operands are of the same vector type, or
@@ -11014,6 +11326,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
LHS = LHSResult.get();
RHS = RHSResult.get();
+ if (Opc == BO_Xor)
+ diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc);
+
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
return InvalidOperands(Loc, LHS, RHS);
@@ -11027,10 +11342,22 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
+ bool EnumConstantInBoolContext = false;
+ for (const ExprResult &HS : {LHS, RHS}) {
+ if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) {
+ const auto *ECDHS = dyn_cast<EnumConstantDecl>(DREHS->getDecl());
+ if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1)
+ EnumConstantInBoolContext = true;
+ }
+ }
+
+ if (EnumConstantInBoolContext)
+ Diag(Loc, diag::warn_enum_constant_in_bool_context);
+
// 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.
- if (LHS.get()->getType()->isIntegerType() &&
+ if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() &&
!LHS.get()->getType()->isBooleanType() &&
RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
// Don't warn in macros or template instantiations.
@@ -11651,6 +11978,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
CheckForNullPointerDereference(*this, LHSExpr);
+ if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) {
+ if (CompoundType.isNull()) {
+ // C++2a [expr.ass]p5:
+ // A simple-assignment whose left operand is of a volatile-qualified
+ // type is deprecated unless the assignment is either a discarded-value
+ // expression or an unevaluated operand
+ ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
+ } else {
+ // C++2a [expr.ass]p6:
+ // [Compound-assignment] expressions are deprecated if E1 has
+ // volatile-qualified type
+ Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
+ }
+ }
+
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
// it is the unqualified version of the type of the left operand.
@@ -11824,11 +12166,11 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
} else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
} else if (S.getLangOpts().ZVector && ResType->isVectorType() &&
- (ResType->getAs<VectorType>()->getVectorKind() !=
+ (ResType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool)) {
// The z vector extensions allow ++ and -- for non-bool vectors.
} else if(S.getLangOpts().OpenCL && ResType->isVectorType() &&
- ResType->getAs<VectorType>()->getElementType()->isIntegerType()) {
+ ResType->castAs<VectorType>()->getElementType()->isIntegerType()) {
// OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types.
} else {
S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
@@ -11839,6 +12181,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// Now make sure the operand is a modifiable lvalue.
if (CheckForModifiableLvalue(Op, OpLoc, S))
return QualType();
+ if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) {
+ // C++2a [expr.pre.inc]p1, [expr.post.inc]p1:
+ // An operand with volatile-qualified type is deprecated
+ S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile)
+ << IsInc << ResType;
+ }
// In C++, a prefix increment is the same type as the operand. Otherwise
// (in C or with postfix), the increment is the unqualified type of the
// operand.
@@ -12414,7 +12762,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
LHS = convertVector(LHS.get(), Context.FloatTy, S);
auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
VK, OK, OpLoc, FPFeatures);
- return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S);
+ return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
}
static std::pair<ExprResult, ExprResult>
@@ -12971,6 +13319,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
RHS->getType(), Functions);
+ // In C++20 onwards, we may have a second operator to look up.
+ if (S.getLangOpts().CPlusPlus2a) {
+ if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))
+ S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(),
+ RHS->getType(), Functions);
+ }
+
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
@@ -13170,7 +13525,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
else if (resultType->isVectorType() &&
// The z vector extensions don't allow + or - with bool vectors.
(!Context.getLangOpts().ZVector ||
- resultType->getAs<VectorType>()->getVectorKind() !=
+ resultType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool))
break;
else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
@@ -13186,7 +13541,6 @@ 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.
@@ -13199,7 +13553,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
// on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ QualType T = resultType->castAs<ExtVectorType>()->getElementType();
if (!T->isIntegerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -13244,7 +13598,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
!Context.getLangOpts().OpenCLCPlusPlus) {
// OpenCL v1.1 6.3.h: The logical operator not (!) does not
// operate on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ QualType T = resultType->castAs<ExtVectorType>()->getElementType();
if (!T->isIntegerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -13728,10 +14082,11 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
if (LangOpts.CPlusPlus) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(Block->getDeclContext(),
- ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Block->getDeclContext());
+ if (MCtx) {
unsigned ManglingNumber = MCtx->getManglingNumber(Block);
Block->setBlockMangling(ManglingNumber, ManglingContextDecl);
}
@@ -13909,7 +14264,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
- const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>();
+ const FunctionType *FTy = BSI->FunctionType->castAs<FunctionType>();
FunctionType::ExtInfo Ext = FTy->getExtInfo();
if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true);
@@ -14381,24 +14736,24 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleObjCQualifiedId: {
if (SrcType->isObjCQualifiedIdType()) {
const ObjCObjectPointerType *srcOPT =
- SrcType->getAs<ObjCObjectPointerType>();
+ SrcType->castAs<ObjCObjectPointerType>();
for (auto *srcProto : srcOPT->quals()) {
PDecl = srcProto;
break;
}
if (const ObjCInterfaceType *IFaceT =
- DstType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ DstType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
else if (DstType->isObjCQualifiedIdType()) {
const ObjCObjectPointerType *dstOPT =
- DstType->getAs<ObjCObjectPointerType>();
+ DstType->castAs<ObjCObjectPointerType>();
for (auto *dstProto : dstOPT->quals()) {
PDecl = dstProto;
break;
}
if (const ObjCInterfaceType *IFaceT =
- SrcType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ SrcType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
DiagKind = diag::warn_incompatible_qualified_id;
@@ -14775,6 +15130,26 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) {
Rec.PossibleDerefs.clear();
}
+/// Check whether E, which is either a discarded-value expression or an
+/// unevaluated operand, is a simple-assignment to a volatlie-qualified lvalue,
+/// and if so, remove it from the list of volatile-qualified assignments that
+/// we are going to warn are deprecated.
+void Sema::CheckUnusedVolatileAssignment(Expr *E) {
+ if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a)
+ return;
+
+ // Note: ignoring parens here is not justified by the standard rules, but
+ // ignoring parentheses seems like a more reasonable approach, and this only
+ // drives a deprecation warning so doesn't affect conformance.
+ if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) {
+ if (BO->getOpcode() == BO_Assign) {
+ auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs;
+ LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()),
+ LHSs.end());
+ }
+ }
+}
+
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
unsigned NumTypos = Rec.NumTypos;
@@ -14809,6 +15184,13 @@ void Sema::PopExpressionEvaluationContext() {
WarnOnPendingNoDerefs(Rec);
+ // Warn on any volatile-qualified simple-assignments that are not discarded-
+ // value expressions nor unevaluated operands (those cases get removed from
+ // this list by CheckUnusedVolatileAssignment).
+ for (auto *BO : Rec.VolatileAssignmentLHSs)
+ Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile)
+ << BO->getType();
+
// When are coming out of an unevaluated context, clear out any
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
@@ -15032,6 +15414,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (IsRecursiveCall && OdrUse == OdrUseContext::Used)
OdrUse = OdrUseContext::FormallyOdrUsed;
+ // Trivial default constructors and destructors are never actually used.
+ // FIXME: What about other special members?
+ if (Func->isTrivial() && !Func->hasAttr<DLLExportAttr>() &&
+ OdrUse == OdrUseContext::Used) {
+ if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Func))
+ if (Constructor->isDefaultConstructor())
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ if (isa<CXXDestructorDecl>(Func))
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ }
+
// C++20 [expr.const]p12:
// A function [...] is needed for constant evaluation if it is [...] a
// constexpr function that is named by an expression that is potentially
@@ -15092,98 +15485,101 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
- Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
- if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
- if (Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial() &&
- !Constructor->hasAttr<DLLExportAttr>())
+ runWithSufficientStackSpace(Loc, [&] {
+ if (CXXConstructorDecl *Constructor =
+ dyn_cast<CXXConstructorDecl>(Func)) {
+ Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
+ if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
+ if (Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial() &&
+ !Constructor->hasAttr<DLLExportAttr>())
+ return;
+ DefineImplicitDefaultConstructor(Loc, Constructor);
+ } else if (Constructor->isCopyConstructor()) {
+ DefineImplicitCopyConstructor(Loc, Constructor);
+ } else if (Constructor->isMoveConstructor()) {
+ DefineImplicitMoveConstructor(Loc, Constructor);
+ }
+ } else if (Constructor->getInheritedConstructor()) {
+ DefineInheritingConstructor(Loc, Constructor);
+ }
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(Func)) {
+ Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+ if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
+ if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
- DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isCopyConstructor()) {
- DefineImplicitCopyConstructor(Loc, Constructor);
- } else if (Constructor->isMoveConstructor()) {
- DefineImplicitMoveConstructor(Loc, Constructor);
+ DefineImplicitDestructor(Loc, Destructor);
}
- } else if (Constructor->getInheritedConstructor()) {
- DefineInheritingConstructor(Loc, Constructor);
- }
- } else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(Func)) {
- Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
- if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
- if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
- return;
- DefineImplicitDestructor(Loc, Destructor);
+ if (Destructor->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, Destructor->getParent());
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
+ if (MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
+ if (MethodDecl->isCopyAssignmentOperator())
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
+ else if (MethodDecl->isMoveAssignmentOperator())
+ DefineImplicitMoveAssignment(Loc, MethodDecl);
+ }
+ } else if (isa<CXXConversionDecl>(MethodDecl) &&
+ MethodDecl->getParent()->isLambda()) {
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
+ if (Conversion->isLambdaToBlockPointerConversion())
+ DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
+ else
+ DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
+ } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
- if (Destructor->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, Destructor->getParent());
- } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
- if (MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal) {
- MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
- if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
- if (MethodDecl->isCopyAssignmentOperator())
- DefineImplicitCopyAssignment(Loc, MethodDecl);
- else if (MethodDecl->isMoveAssignmentOperator())
- DefineImplicitMoveAssignment(Loc, MethodDecl);
- }
- } else if (isa<CXXConversionDecl>(MethodDecl) &&
- MethodDecl->getParent()->isLambda()) {
- CXXConversionDecl *Conversion =
- cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
- if (Conversion->isLambdaToBlockPointerConversion())
- DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
- else
- DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
- } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, MethodDecl->getParent());
- }
- // Implicit instantiation of function templates and member functions of
- // class templates.
- if (Func->isImplicitlyInstantiable()) {
- TemplateSpecializationKind TSK =
- Func->getTemplateSpecializationKindForInstantiation();
- SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
- bool FirstInstantiation = PointOfInstantiation.isInvalid();
- if (FirstInstantiation) {
- PointOfInstantiation = Loc;
- Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- } else if (TSK != TSK_ImplicitInstantiation) {
- // Use the point of use as the point of instantiation, instead of the
- // point of explicit instantiation (which we track as the actual point
- // of instantiation). This gives better backtraces in diagnostics.
- PointOfInstantiation = Loc;
- }
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
+ if (Func->isImplicitlyInstantiable()) {
+ TemplateSpecializationKind TSK =
+ Func->getTemplateSpecializationKindForInstantiation();
+ SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
+ bool FirstInstantiation = PointOfInstantiation.isInvalid();
+ if (FirstInstantiation) {
+ PointOfInstantiation = Loc;
+ Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ } else if (TSK != TSK_ImplicitInstantiation) {
+ // Use the point of use as the point of instantiation, instead of the
+ // point of explicit instantiation (which we track as the actual point
+ // of instantiation). This gives better backtraces in diagnostics.
+ PointOfInstantiation = Loc;
+ }
- if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
- Func->isConstexpr()) {
- if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
- cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
- CodeSynthesisContexts.size())
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- else if (Func->isConstexpr())
- // Do not defer instantiations of constexpr functions, to avoid the
- // expression evaluator needing to call back into Sema if it sees a
- // call to such a function.
- InstantiateFunctionDefinition(PointOfInstantiation, Func);
- else {
- Func->setInstantiationIsPending(true);
- PendingInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- // Notify the consumer that a function was implicitly instantiated.
- Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
+ Func->isConstexpr()) {
+ if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+ CodeSynthesisContexts.size())
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ else if (Func->isConstexpr())
+ // Do not defer instantiations of constexpr functions, to avoid the
+ // expression evaluator needing to call back into Sema if it sees a
+ // call to such a function.
+ InstantiateFunctionDefinition(PointOfInstantiation, Func);
+ else {
+ Func->setInstantiationIsPending(true);
+ PendingInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ // Notify the consumer that a function was implicitly instantiated.
+ Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ }
+ }
+ } else {
+ // Walk redefinitions, as some of them may be instantiable.
+ for (auto i : Func->redecls()) {
+ if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+ MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
}
- } else {
- // Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
- if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, i, MightBeOdrUse);
- }
- }
+ });
}
// If this is the first "real" use, act on that.
@@ -15207,9 +15603,14 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
CheckCompleteParameterTypesForMangler(*this, Func, Loc);
Func->markUsed(Context);
+ }
- if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+ if (LangOpts.OpenMP) {
+ markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse);
+ if (LangOpts.OpenMPIsDevice)
checkOpenMPDeviceFunction(Loc, Func);
+ else
+ checkOpenMPHostFunction(Loc, Func);
}
}
@@ -15447,27 +15848,11 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
if (const auto *PT = CaptureType->getAs<PointerType>()) {
- // This function finds out whether there is an AttributedType of kind
- // attr::ObjCOwnership in Ty. The existence of AttributedType of kind
- // attr::ObjCOwnership implies __autoreleasing was explicitly specified
- // rather than being added implicitly by the compiler.
- auto IsObjCOwnershipAttributedType = [](QualType Ty) {
- while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
- if (AttrTy->getAttrKind() == attr::ObjCOwnership)
- return true;
-
- // Peel off AttributedTypes that are not of kind ObjCOwnership.
- Ty = AttrTy->getModifiedType();
- }
-
- return false;
- };
-
QualType PointeeTy = PT->getPointeeType();
if (!Invalid && PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
- !IsObjCOwnershipAttributedType(PointeeTy)) {
+ !S.Context.hasDirectOwnershipQualifier(PointeeTy)) {
if (BuildAndDiagnose) {
SourceLocation VarLoc = Var->getLocation();
S.Diag(Loc, diag::warn_block_capture_autoreleasing);
@@ -15517,7 +15902,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
if (HasConst)
DeclRefType.addConst();
}
- ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel);
+ ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel);
}
if (ByRef)
@@ -15745,7 +16131,25 @@ bool Sema::tryCaptureVariable(
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel);
- auto IsTargetCap = !IsOpenMPPrivateDecl &&
+ // If the variable is private (i.e. not captured) and has variably
+ // modified type, we still need to capture the type for correct
+ // codegen in all regions, associated with the construct. Currently,
+ // it is captured in the innermost captured region only.
+ if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) {
+ QualType QTy = Var->getType();
+ if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
+ QTy = PVD->getOriginalType();
+ for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel);
+ I < E; ++I) {
+ auto *OuterRSI = cast<CapturedRegionScopeInfo>(
+ FunctionScopes[FunctionScopesIndex - I]);
+ assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel &&
+ "Wrong number of captured regions associated with the "
+ "OpenMP construct.");
+ captureVariablyModifiedType(Context, QTy, OuterRSI);
+ }
+ }
+ bool IsTargetCap = !IsOpenMPPrivateDecl &&
isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
// When we detect target captures we are looking from inside the
// target region, therefore we need to propagate the capture from the
@@ -16354,7 +16758,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (UsableInConstantExpr) {
// Do not defer instantiations of variables that could be used in a
// constant expression.
- SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
} else if (FirstInstantiation ||
isa<VarTemplateSpecializationDecl>(Var)) {
// FIXME: For a specialization of a variable template, we don't
@@ -17546,6 +17952,9 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
#define PLACEHOLDER_TYPE(Id, SingletonId)
#include "clang/AST/BuiltinTypes.def"