aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp775
1 files changed, 572 insertions, 203 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index b62f3c475c45..c6218a491aec 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
@@ -37,15 +38,18 @@
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/SaveAndRestore.h"
#include <map>
#include <optional>
@@ -83,7 +87,8 @@ public:
bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
bool IsInvalid = false;
for (const Stmt *SubStmt : Node->children())
- IsInvalid |= Visit(SubStmt);
+ if (SubStmt)
+ IsInvalid |= Visit(SubStmt);
return IsInvalid;
}
@@ -329,23 +334,16 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
ParmVarDecl *Param = cast<ParmVarDecl>(param);
UnparsedDefaultArgLocs.erase(Param);
- auto Fail = [&] {
- Param->setInvalidDecl();
- Param->setDefaultArg(new (Context) OpaqueValueExpr(
- EqualLoc, Param->getType().getNonReferenceType(), VK_PRValue));
- };
-
// Default arguments are only permitted in C++
if (!getLangOpts().CPlusPlus) {
Diag(EqualLoc, diag::err_param_default_argument)
<< DefaultArg->getSourceRange();
- return Fail();
+ return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
}
// Check for unexpanded parameter packs.
- if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) {
- return Fail();
- }
+ if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument))
+ return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
// C++11 [dcl.fct.default]p3
// A default argument expression [...] shall not be specified for a
@@ -360,14 +358,14 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
ExprResult Result = ConvertParamDefaultArgument(Param, DefaultArg, EqualLoc);
if (Result.isInvalid())
- return Fail();
+ return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
DefaultArg = Result.getAs<Expr>();
// Check that the default argument is well-formed
CheckDefaultArgumentVisitor DefaultArgChecker(*this, DefaultArg);
if (DefaultArgChecker.Visit(DefaultArg))
- return Fail();
+ return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
SetParamDefaultArgument(Param, DefaultArg, EqualLoc);
}
@@ -389,16 +387,23 @@ void Sema::ActOnParamUnparsedDefaultArgument(Decl *param,
/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
/// the default argument for the parameter param failed.
-void Sema::ActOnParamDefaultArgumentError(Decl *param,
- SourceLocation EqualLoc) {
+void Sema::ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc,
+ Expr *DefaultArg) {
if (!param)
return;
ParmVarDecl *Param = cast<ParmVarDecl>(param);
Param->setInvalidDecl();
UnparsedDefaultArgLocs.erase(Param);
- Param->setDefaultArg(new (Context) OpaqueValueExpr(
- EqualLoc, Param->getType().getNonReferenceType(), VK_PRValue));
+ ExprResult RE;
+ if (DefaultArg) {
+ RE = CreateRecoveryExpr(EqualLoc, DefaultArg->getEndLoc(), {DefaultArg},
+ Param->getType().getNonReferenceType());
+ } else {
+ RE = CreateRecoveryExpr(EqualLoc, EqualLoc, {},
+ Param->getType().getNonReferenceType());
+ }
+ Param->setDefaultArg(RE.get());
}
/// CheckExtraCXXDefaultArguments - Check for any extra default
@@ -723,6 +728,12 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
return Invalid;
}
+void Sema::DiagPlaceholderVariableDefinition(SourceLocation Loc) {
+ Diag(Loc, getLangOpts().CPlusPlus26
+ ? diag::warn_cxx23_placeholder_var_definition
+ : diag::ext_placeholder_var_definition);
+}
+
NamedDecl *
Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists) {
@@ -878,6 +889,9 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
for (auto &B : D.getDecompositionDeclarator().bindings()) {
// Check for name conflicts.
DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
+ IdentifierInfo *VarName = B.Name;
+ assert(VarName && "Cannot have an unnamed binding declaration");
+
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
ForVisibleRedeclaration);
LookupName(Previous, S,
@@ -891,7 +905,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
Previous.clear();
}
- auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);
+ auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, VarName);
// Find the shadowed declaration before filtering for scope.
NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty()
@@ -903,10 +917,24 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
FilterLookupForScope(Previous, DC, S, ConsiderLinkage,
/*AllowInlineNamespace*/false);
+ bool IsPlaceholder = DS.getStorageClassSpec() != DeclSpec::SCS_static &&
+ DC->isFunctionOrMethod() && VarName->isPlaceholder();
if (!Previous.empty()) {
- auto *Old = Previous.getRepresentativeDecl();
- Diag(B.NameLoc, diag::err_redefinition) << B.Name;
- Diag(Old->getLocation(), diag::note_previous_definition);
+ if (IsPlaceholder) {
+ bool sameDC = (Previous.end() - 1)
+ ->getDeclContext()
+ ->getRedeclContext()
+ ->Equals(DC->getRedeclContext());
+ if (sameDC &&
+ isDeclInScope(*(Previous.end() - 1), CurContext, S, false)) {
+ Previous.clear();
+ DiagPlaceholderVariableDefinition(B.NameLoc);
+ }
+ } else {
+ auto *Old = Previous.getRepresentativeDecl();
+ Diag(B.NameLoc, diag::err_redefinition) << B.Name;
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ }
} else if (ShadowedDecl && !D.isRedeclaration()) {
CheckShadow(BD, ShadowedDecl, Previous);
}
@@ -1271,8 +1299,9 @@ static bool checkTupleLikeDecomposition(Sema &S,
// in the associated namespaces.
Expr *Get = UnresolvedLookupExpr::Create(
S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
- DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args,
- UnresolvedSetIterator(), UnresolvedSetIterator());
+ DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/ true, &Args,
+ UnresolvedSetIterator(), UnresolvedSetIterator(),
+ /*KnownDependent=*/false);
Expr *Arg = E.get();
E = S.BuildCallExpr(nullptr, Get, Loc, Arg, Loc);
@@ -1752,9 +1781,12 @@ static bool CheckConstexprReturnType(Sema &SemaRef, const FunctionDecl *FD,
/// \returns diagnostic %select index.
static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
switch (Tag) {
- case TTK_Struct: return 0;
- case TTK_Interface: return 1;
- case TTK_Class: return 2;
+ case TagTypeKind::Struct:
+ return 0;
+ case TagTypeKind::Interface:
+ return 1;
+ case TagTypeKind::Class:
+ return 2;
default: llvm_unreachable("Invalid tag kind for record diagnostic!");
}
}
@@ -2428,7 +2460,8 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
!Expr::isPotentialConstantExpr(Dcl, Diags)) {
SemaRef.Diag(Dcl->getLocation(),
diag::ext_constexpr_function_never_constant_expr)
- << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
+ << Dcl->getNameInfo().getSourceRange();
for (size_t I = 0, N = Diags.size(); I != N; ++I)
SemaRef.Diag(Diags[I].first, Diags[I].second);
// Don't return false here: we allow this for compatibility in
@@ -2488,12 +2521,15 @@ void Sema::DiagnoseImmediateEscalatingReason(FunctionDecl *FD) {
Range = CurrentInit->isWritten() ? CurrentInit->getSourceRange()
: SourceRange();
}
+
+ FieldDecl* InitializedField = CurrentInit ? CurrentInit->getAnyMember() : nullptr;
+
SemaRef.Diag(Loc, diag::note_immediate_function_reason)
<< ImmediateFn << Fn << Fn->isConsteval() << IsCall
<< isa<CXXConstructorDecl>(Fn) << ImmediateFnIsConstructor
- << (CurrentInit != nullptr)
+ << (InitializedField != nullptr)
<< (CurrentInit && !CurrentInit->isWritten())
- << (CurrentInit ? CurrentInit->getAnyMember() : nullptr) << Range;
+ << InitializedField << Range;
}
bool TraverseCallExpr(CallExpr *E) {
if (const auto *DR =
@@ -2647,7 +2683,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
TypeSourceInfo *TInfo,
SourceLocation EllipsisLoc) {
// In HLSL, unspecified class access is public rather than private.
- if (getLangOpts().HLSL && Class->getTagKind() == TTK_Class &&
+ if (getLangOpts().HLSL && Class->getTagKind() == TagTypeKind::Class &&
Access == AS_none)
Access = AS_public;
@@ -2700,9 +2736,9 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// emitted.
if (!Class->getTypeForDecl()->isDependentType())
Class->setInvalidDecl();
- return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == TTK_Class,
- Access, TInfo, EllipsisLoc);
+ return new (Context) CXXBaseSpecifier(
+ SpecifierRange, Virtual, Class->getTagKind() == TagTypeKind::Class,
+ Access, TInfo, EllipsisLoc);
}
// Base specifiers must be record types.
@@ -2788,9 +2824,9 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
Class->setInvalidDecl();
// Create the base specifier.
- return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == TTK_Class,
- Access, TInfo, EllipsisLoc);
+ return new (Context) CXXBaseSpecifier(
+ SpecifierRange, Virtual, Class->getTagKind() == TagTypeKind::Class,
+ Access, TInfo, EllipsisLoc);
}
/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
@@ -3703,10 +3739,20 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (!Diags.isIgnored(diag::warn_unused_private_field, FD->getLocation())) {
// Remember all explicit private FieldDecls that have a name, no side
// effects and are not part of a dependent type declaration.
+
+ auto DeclHasUnusedAttr = [](const QualType &T) {
+ if (const TagDecl *TD = T->getAsTagDecl())
+ return TD->hasAttr<UnusedAttr>();
+ if (const TypedefType *TDT = T->getAs<TypedefType>())
+ return TDT->getDecl()->hasAttr<UnusedAttr>();
+ return false;
+ };
+
if (!FD->isImplicit() && FD->getDeclName() &&
FD->getAccess() == AS_private &&
!FD->hasAttr<UnusedAttr>() &&
!FD->getParent()->isDependentContext() &&
+ !DeclHasUnusedAttr(FD->getType()) &&
!InitializationHasSideEffects(*FD))
UnusedPrivateFields.insert(FD);
}
@@ -4327,16 +4373,57 @@ private:
}
+bool Sema::DiagRedefinedPlaceholderFieldDecl(SourceLocation Loc,
+ RecordDecl *ClassDecl,
+ const IdentifierInfo *Name) {
+ DeclContextLookupResult Result = ClassDecl->lookup(Name);
+ DeclContextLookupResult::iterator Found =
+ llvm::find_if(Result, [this](const NamedDecl *Elem) {
+ return isa<FieldDecl, IndirectFieldDecl>(Elem) &&
+ Elem->isPlaceholderVar(getLangOpts());
+ });
+ // We did not find a placeholder variable
+ if (Found == Result.end())
+ return false;
+ Diag(Loc, diag::err_using_placeholder_variable) << Name;
+ for (DeclContextLookupResult::iterator It = Found; It != Result.end(); It++) {
+ const NamedDecl *ND = *It;
+ if (ND->getDeclContext() != ND->getDeclContext())
+ break;
+ if (isa<FieldDecl, IndirectFieldDecl>(ND) &&
+ ND->isPlaceholderVar(getLangOpts()))
+ Diag(ND->getLocation(), diag::note_reference_placeholder) << ND;
+ }
+ return true;
+}
+
+ValueDecl *
+Sema::tryLookupUnambiguousFieldDecl(RecordDecl *ClassDecl,
+ const IdentifierInfo *MemberOrBase) {
+ ValueDecl *ND = nullptr;
+ for (auto *D : ClassDecl->lookup(MemberOrBase)) {
+ if (isa<FieldDecl, IndirectFieldDecl>(D)) {
+ bool IsPlaceholder = D->isPlaceholderVar(getLangOpts());
+ if (ND) {
+ if (IsPlaceholder && D->getDeclContext() == ND->getDeclContext())
+ return nullptr;
+ break;
+ }
+ if (!IsPlaceholder)
+ return cast<ValueDecl>(D);
+ ND = cast<ValueDecl>(D);
+ }
+ }
+ return ND;
+}
+
ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl,
CXXScopeSpec &SS,
ParsedType TemplateTypeTy,
IdentifierInfo *MemberOrBase) {
if (SS.getScopeRep() || TemplateTypeTy)
return nullptr;
- for (auto *D : ClassDecl->lookup(MemberOrBase))
- if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D))
- return cast<ValueDecl>(D);
- return nullptr;
+ return tryLookupUnambiguousFieldDecl(ClassDecl, MemberOrBase);
}
/// Handle a C++ member initializer.
@@ -4427,9 +4514,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (!NotUnknownSpecialization) {
// When the scope specifier can refer to a member of an unknown
// specialization, we take it as a type name.
- BaseType = CheckTypenameType(ETK_None, SourceLocation(),
- SS.getWithLocInContext(Context),
- *MemberOrBase, IdLoc);
+ BaseType = CheckTypenameType(
+ ElaboratedTypeKeyword::None, SourceLocation(),
+ SS.getWithLocInContext(Context), *MemberOrBase, IdLoc);
if (BaseType.isNull())
return true;
@@ -4512,7 +4599,8 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
if (BaseType.isNull()) {
- BaseType = getElaboratedType(ETK_None, SS, Context.getTypeDeclType(TyD));
+ BaseType = getElaboratedType(ElaboratedTypeKeyword::None, SS,
+ Context.getTypeDeclType(TyD));
MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false);
TInfo = Context.CreateTypeSourceInfo(BaseType);
ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>();
@@ -6925,7 +7013,7 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
(F->getType().isConstQualified() && F->getType()->isScalarType())) {
if (!Complained) {
Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst)
- << Record->getTagKind() << Record;
+ << llvm::to_underlying(Record->getTagKind()) << Record;
Complained = true;
}
@@ -7195,11 +7283,12 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
bool CanPass = canPassInRegisters(*this, Record, CCK);
// Do not change ArgPassingRestrictions if it has already been set to
- // APK_CanNeverPassInRegs.
- if (Record->getArgPassingRestrictions() != RecordDecl::APK_CanNeverPassInRegs)
- Record->setArgPassingRestrictions(CanPass
- ? RecordDecl::APK_CanPassInRegs
- : RecordDecl::APK_CannotPassInRegs);
+ // ArgPassingKind::CanNeverPassInRegs.
+ if (Record->getArgPassingRestrictions() !=
+ RecordArgPassingKind::CanNeverPassInRegs)
+ Record->setArgPassingRestrictions(
+ CanPass ? RecordArgPassingKind::CanPassInRegs
+ : RecordArgPassingKind::CannotPassInRegs);
// If canPassInRegisters returns true despite the record having a non-trivial
// destructor, the record is destructed in the callee. This happens only when
@@ -7611,7 +7700,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
unsigned ExpectedParams = 1;
if (CSM == CXXDefaultConstructor || CSM == CXXDestructor)
ExpectedParams = 0;
- if (MD->getNumParams() != ExpectedParams) {
+ if (MD->getNumExplicitParams() != ExpectedParams) {
// This checks for default arguments: a copy or move constructor with a
// default argument is classified as a default constructor, and assignment
// operations and destructors can't have default arguments.
@@ -7640,10 +7729,13 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
// Check for return type matching.
ReturnType = Type->getReturnType();
+ QualType ThisType = MD->getFunctionObjectParameterType();
QualType DeclType = Context.getTypeDeclType(RD);
- DeclType = Context.getElaboratedType(ETK_None, nullptr, DeclType, nullptr);
- DeclType = Context.getAddrSpaceQualType(DeclType, MD->getMethodQualifiers().getAddressSpace());
+ DeclType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr,
+ DeclType, nullptr);
+ DeclType = Context.getAddrSpaceQualType(
+ DeclType, ThisType.getQualifiers().getAddressSpace());
QualType ExpectedReturnType = Context.getLValueReferenceType(DeclType);
if (!Context.hasSameType(ReturnType, ExpectedReturnType)) {
@@ -7653,7 +7745,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
}
// A defaulted special member cannot have cv-qualifiers.
- if (Type->getMethodQuals().hasConst() || Type->getMethodQuals().hasVolatile()) {
+ if (ThisType.isConstQualified() || ThisType.isVolatileQualified()) {
if (DeleteOnTypeMismatch)
ShouldDeleteForTypeMismatch = true;
else {
@@ -7662,10 +7754,31 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
HadError = true;
}
}
+ // [C++23][dcl.fct.def.default]/p2.2
+ // if F2 has an implicit object parameter of type “reference to C”,
+ // F1 may be an explicit object member function whose explicit object
+ // parameter is of (possibly different) type “reference to C”,
+ // in which case the type of F1 would differ from the type of F2
+ // in that the type of F1 has an additional parameter;
+ if (!Context.hasSameType(
+ ThisType.getNonReferenceType().getUnqualifiedType(),
+ Context.getRecordType(RD))) {
+ if (DeleteOnTypeMismatch)
+ ShouldDeleteForTypeMismatch = true;
+ else {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_explicit_object_mismatch)
+ << (CSM == CXXMoveAssignment) << RD << MD->getSourceRange();
+ HadError = true;
+ }
+ }
}
// Check for parameter type matching.
- QualType ArgType = ExpectedParams ? Type->getParamType(0) : QualType();
+ QualType ArgType =
+ ExpectedParams
+ ? Type->getParamType(MD->isExplicitObjectMemberFunction() ? 1 : 0)
+ : QualType();
bool HasConstParam = false;
if (ExpectedParams && ArgType->isReferenceType()) {
// Argument must be reference to possibly-const T.
@@ -7733,10 +7846,17 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
: isa<CXXConstructorDecl>(MD))) &&
MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- Diag(MD->getBeginLoc(), MD->isConsteval()
- ? diag::err_incorrect_defaulted_consteval
- : diag::err_incorrect_defaulted_constexpr)
- << CSM;
+ if (!MD->isConsteval() && RD->getNumVBases()) {
+ Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr_with_vb)
+ << CSM;
+ for (const auto &I : RD->vbases())
+ Diag(I.getBeginLoc(), diag::note_constexpr_virtual_base_here);
+ } else {
+ Diag(MD->getBeginLoc(), MD->isConsteval()
+ ? diag::err_incorrect_defaulted_consteval
+ : diag::err_incorrect_defaulted_constexpr)
+ << CSM;
+ }
// FIXME: Explain why the special member can't be constexpr.
HadError = true;
}
@@ -7759,8 +7879,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
EPI.ExceptionSpec.Type = EST_Unevaluated;
EPI.ExceptionSpec.SourceDecl = MD;
- MD->setType(Context.getFunctionType(
- ReturnType, llvm::ArrayRef(&ArgType, ExpectedParams), EPI));
+ MD->setType(
+ Context.getFunctionType(ReturnType, Type->getParamTypes(), EPI));
}
}
@@ -8411,7 +8531,8 @@ private:
ExprPair getCompleteObject() {
unsigned Param = 0;
ExprResult LHS;
- if (isa<CXXMethodDecl>(FD)) {
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD);
+ MD && MD->isImplicitObjectMemberFunction()) {
// LHS is '*this'.
LHS = S.ActOnCXXThis(Loc);
if (!LHS.isInvalid())
@@ -8717,15 +8838,22 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
// If we're out-of-class, this is the class we're comparing.
if (!RD)
RD = MD->getParent();
-
- if (!MD->isConst()) {
- SourceLocation InsertLoc;
- if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc())
- InsertLoc = getLocForEndOfToken(Loc.getRParenLoc());
+ QualType T = MD->getFunctionObjectParameterType();
+ if (!T.isConstQualified()) {
+ SourceLocation Loc, InsertLoc;
+ if (MD->isExplicitObjectMemberFunction()) {
+ Loc = MD->getParamDecl(0)->getBeginLoc();
+ InsertLoc = getLocForEndOfToken(
+ MD->getParamDecl(0)->getExplicitObjectParamThisLoc());
+ } else {
+ Loc = MD->getLocation();
+ if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc())
+ InsertLoc = Loc.getRParenLoc();
+ }
// Don't diagnose an implicit 'operator=='; we will have diagnosed the
// corresponding defaulted 'operator<=>' already.
if (!MD->isImplicit()) {
- Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const)
+ Diag(Loc, diag::err_defaulted_comparison_non_const)
<< (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const");
}
@@ -8749,7 +8877,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
}
}
- if (FD->getNumParams() != (IsMethod ? 1 : 2)) {
+ if ((FD->getNumParams() -
+ (unsigned)FD->hasCXXExplicitFunctionObjectParameter()) !=
+ (IsMethod ? 1 : 2)) {
// Let's not worry about using a variadic template pack here -- who would do
// such a thing?
Diag(FD->getLocation(), diag::err_defaulted_comparison_num_args)
@@ -8759,6 +8889,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
const ParmVarDecl *KnownParm = nullptr;
for (const ParmVarDecl *Param : FD->parameters()) {
+ if (Param->isExplicitObjectParameter())
+ continue;
QualType ParmTy = Param->getType();
if (!KnownParm) {
@@ -9142,9 +9274,9 @@ struct SpecialMemberVisitor {
llvm_unreachable("invalid special member kind");
}
- if (MD->getNumParams()) {
+ if (MD->getNumExplicitParams()) {
if (const ReferenceType *RT =
- MD->getParamDecl(0)->getType()->getAs<ReferenceType>())
+ MD->getNonObjectParameter(0)->getType()->getAs<ReferenceType>())
ConstArg = RT->getPointeeType().isConstQualified();
}
}
@@ -10024,7 +10156,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
case CXXCopyConstructor:
case CXXCopyAssignment: {
- const ParmVarDecl *Param0 = MD->getParamDecl(0);
+ const ParmVarDecl *Param0 = MD->getNonObjectParameter(0);
const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
// When ClangABICompat14 is true, CXX copy constructors will only be trivial
@@ -10055,7 +10187,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
case CXXMoveConstructor:
case CXXMoveAssignment: {
// Trivial move operations always have non-cv-qualified parameters.
- const ParmVarDecl *Param0 = MD->getParamDecl(0);
+ const ParmVarDecl *Param0 = MD->getNonObjectParameter(0);
const RValueReferenceType *RT =
Param0->getType()->getAs<RValueReferenceType>();
if (!RT || RT->getPointeeType().getCVRQualifiers()) {
@@ -11021,15 +11153,25 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
<< SourceRange(D.getIdentifierLoc()) << 0;
D.setInvalidType();
}
-
const auto *Proto = R->castAs<FunctionProtoType>();
-
// Make sure we don't have any parameters.
- if (Proto->getNumParams() > 0) {
- Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+ unsigned NumParam = Proto->getNumParams();
+
+ // [C++2b]
+ // A conversion function shall have no non-object parameters.
+ if (NumParam == 1) {
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+ if (const auto *First =
+ dyn_cast_if_present<ParmVarDecl>(FTI.Params[0].Param);
+ First && First->isExplicitObjectParameter())
+ NumParam--;
+ }
+ if (NumParam != 0) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
- D.getFunctionTypeInfo().freeParams();
+ FTI.freeParams();
D.setInvalidType();
} else if (Proto->isVariadic()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
@@ -11187,6 +11329,92 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
return Conversion;
}
+void Sema::CheckExplicitObjectMemberFunction(DeclContext *DC, Declarator &D,
+ DeclarationName Name, QualType R) {
+ CheckExplicitObjectMemberFunction(D, Name, R, false, DC);
+}
+
+void Sema::CheckExplicitObjectLambda(Declarator &D) {
+ CheckExplicitObjectMemberFunction(D, {}, {}, true);
+}
+
+void Sema::CheckExplicitObjectMemberFunction(Declarator &D,
+ DeclarationName Name, QualType R,
+ bool IsLambda, DeclContext *DC) {
+ if (!D.isFunctionDeclarator())
+ return;
+
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+ if (FTI.NumParams == 0)
+ return;
+ ParmVarDecl *ExplicitObjectParam = nullptr;
+ for (unsigned Idx = 0; Idx < FTI.NumParams; Idx++) {
+ const auto &ParamInfo = FTI.Params[Idx];
+ if (!ParamInfo.Param)
+ continue;
+ ParmVarDecl *Param = cast<ParmVarDecl>(ParamInfo.Param);
+ if (!Param->isExplicitObjectParameter())
+ continue;
+ if (Idx == 0) {
+ ExplicitObjectParam = Param;
+ continue;
+ } else {
+ Diag(Param->getLocation(),
+ diag::err_explicit_object_parameter_must_be_first)
+ << IsLambda << Param->getSourceRange();
+ }
+ }
+ if (!ExplicitObjectParam)
+ return;
+
+ if (ExplicitObjectParam->hasDefaultArg()) {
+ Diag(ExplicitObjectParam->getLocation(),
+ diag::err_explicit_object_default_arg)
+ << ExplicitObjectParam->getSourceRange();
+ }
+
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) {
+ Diag(ExplicitObjectParam->getBeginLoc(),
+ diag::err_explicit_object_parameter_nonmember)
+ << D.getSourceRange() << /*static=*/0 << IsLambda;
+ D.setInvalidType();
+ }
+
+ if (D.getDeclSpec().isVirtualSpecified()) {
+ Diag(ExplicitObjectParam->getBeginLoc(),
+ diag::err_explicit_object_parameter_nonmember)
+ << D.getSourceRange() << /*virtual=*/1 << IsLambda;
+ D.setInvalidType();
+ }
+
+ if (IsLambda && FTI.hasMutableQualifier()) {
+ Diag(ExplicitObjectParam->getBeginLoc(),
+ diag::err_explicit_object_parameter_mutable)
+ << D.getSourceRange();
+ }
+
+ if (IsLambda)
+ return;
+
+ if (!DC || !DC->isRecord()) {
+ Diag(ExplicitObjectParam->getLocation(),
+ diag::err_explicit_object_parameter_nonmember)
+ << D.getSourceRange() << /*non-member=*/2 << IsLambda;
+ D.setInvalidType();
+ return;
+ }
+
+ // CWG2674: constructors and destructors cannot have explicit parameters.
+ if (Name.getNameKind() == DeclarationName::CXXConstructorName ||
+ Name.getNameKind() == DeclarationName::CXXDestructorName) {
+ Diag(ExplicitObjectParam->getBeginLoc(),
+ diag::err_explicit_object_parameter_constructor)
+ << (Name.getNameKind() == DeclarationName::CXXDestructorName)
+ << D.getSourceRange();
+ D.setInvalidType();
+ }
+}
+
namespace {
/// Utility class to accumulate and print a diagnostic listing the invalid
/// specifier(s) on a declaration.
@@ -11234,7 +11462,7 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
GuidedTemplateDecl->getDeclContext()->getRedeclContext())) {
Diag(D.getIdentifierLoc(), diag::err_deduction_guide_wrong_scope)
<< GuidedTemplateDecl;
- Diag(GuidedTemplateDecl->getLocation(), diag::note_template_decl_here);
+ NoteTemplateLocation(*GuidedTemplateDecl);
}
auto &DS = D.getMutableDeclSpec();
@@ -11614,7 +11842,8 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
auto TyForDiags = [&](ComparisonCategoryInfo *Info) {
auto *NNS =
NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
- return Context.getElaboratedType(ETK_None, NNS, Info->getType());
+ return Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS,
+ Info->getType());
};
// Check if we've already successfully checked the comparison category type
@@ -11833,7 +12062,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
Context.getTrivialTypeSourceInfo(Element,
Loc)));
return Context.getElaboratedType(
- ElaboratedTypeKeyword::ETK_None,
+ ElaboratedTypeKeyword::None,
NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()),
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
}
@@ -11885,6 +12114,24 @@ public:
}
+static void DiagnoseInvisibleNamespace(const TypoCorrection &Corrected,
+ Sema &S) {
+ auto *ND = cast<NamespaceDecl>(Corrected.getFoundDecl());
+ Module *M = ND->getOwningModule();
+ assert(M && "hidden namespace definition not in a module?");
+
+ if (M->isExplicitGlobalModule())
+ S.Diag(Corrected.getCorrectionRange().getBegin(),
+ diag::err_module_unimported_use_header)
+ << (int)Sema::MissingImportKind::Declaration << Corrected.getFoundDecl()
+ << /*Header Name*/ false;
+ else
+ S.Diag(Corrected.getCorrectionRange().getBegin(),
+ diag::err_module_unimported_use)
+ << (int)Sema::MissingImportKind::Declaration << Corrected.getFoundDecl()
+ << M->getTopLevelModuleName();
+}
+
static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
CXXScopeSpec &SS,
SourceLocation IdentLoc,
@@ -11894,7 +12141,16 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
if (TypoCorrection Corrected =
S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS, CCC,
Sema::CTK_ErrorRecovery)) {
- if (DeclContext *DC = S.computeDeclContext(SS, false)) {
+ // Generally we find it is confusing more than helpful to diagnose the
+ // invisible namespace.
+ // See https://github.com/llvm/llvm-project/issues/73893.
+ //
+ // However, we should diagnose when the users are trying to using an
+ // invisible namespace. So we handle the case specially here.
+ if (isa_and_nonnull<NamespaceDecl>(Corrected.getFoundDecl()) &&
+ Corrected.requiresImport()) {
+ DiagnoseInvisibleNamespace(Corrected, S);
+ } else if (DeclContext *DC = S.computeDeclContext(SS, false)) {
std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
Ident->getName().equals(CorrectedStr);
@@ -14615,7 +14871,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
- ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
+ ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr,
+ ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ArgType, AS);
@@ -14781,12 +15038,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
SmallVector<Stmt*, 8> Statements;
// The parameter for the "other" object, which we are copying from.
- ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
+ ParmVarDecl *Other = CopyAssignOperator->getNonObjectParameter(0);
Qualifiers OtherQuals = Other->getType().getQualifiers();
QualType OtherRefType = Other->getType();
- if (const LValueReferenceType *OtherRef
- = OtherRefType->getAs<LValueReferenceType>()) {
- OtherRefType = OtherRef->getPointeeType();
+ if (OtherRefType->isLValueReferenceType()) {
+ OtherRefType = OtherRefType->getPointeeType();
OtherQuals = OtherRefType.getQualifiers();
}
@@ -14798,8 +15054,26 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Builds a DeclRefExpr for the "other" object.
RefBuilder OtherRef(Other, OtherRefType);
- // Builds the "this" pointer.
- ThisBuilder This;
+ // Builds the function object parameter.
+ std::optional<ThisBuilder> This;
+ std::optional<DerefBuilder> DerefThis;
+ std::optional<RefBuilder> ExplicitObject;
+ bool IsArrow = false;
+ QualType ObjectType;
+ if (CopyAssignOperator->isExplicitObjectMemberFunction()) {
+ ObjectType = CopyAssignOperator->getParamDecl(0)->getType();
+ if (ObjectType->isReferenceType())
+ ObjectType = ObjectType->getPointeeType();
+ ExplicitObject.emplace(CopyAssignOperator->getParamDecl(0), ObjectType);
+ } else {
+ ObjectType = getCurrentThisType();
+ This.emplace();
+ DerefThis.emplace(*This);
+ IsArrow = !LangOpts.HLSL;
+ }
+ ExprBuilder &ObjectParameter =
+ ExplicitObject ? static_cast<ExprBuilder &>(*ExplicitObject)
+ : static_cast<ExprBuilder &>(*This);
// Assign base classes.
bool Invalid = false;
@@ -14821,11 +15095,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
VK_LValue, BasePath);
// Dereference "this".
- DerefBuilder DerefThis(This);
- CastBuilder To(DerefThis,
- Context.getQualifiedType(
- BaseType, CopyAssignOperator->getMethodQualifiers()),
- VK_LValue, BasePath);
+ CastBuilder To(
+ ExplicitObject ? static_cast<ExprBuilder &>(*ExplicitObject)
+ : static_cast<ExprBuilder &>(*DerefThis),
+ Context.getQualifiedType(BaseType, ObjectType.getQualifiers()),
+ VK_LValue, BasePath);
// Build the copy.
StmtResult Copy = buildSingleCopyAssign(*this, Loc, BaseType,
@@ -14891,10 +15165,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
MemberLookup.resolveKind();
MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup);
-
- MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/!LangOpts.HLSL,
- MemberLookup);
-
+ MemberBuilder To(ObjectParameter, ObjectType, IsArrow, MemberLookup);
// Build the copy of this field.
StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType,
To, From,
@@ -14911,15 +15182,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
- Expr *ThisExpr = nullptr;
- if (!LangOpts.HLSL) {
- ExprResult ThisObj =
- CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
- ThisExpr = ThisObj.get();
- } else {
- ThisExpr = This.build(*this, Loc);
- }
-
+ Expr *ThisExpr =
+ (ExplicitObject ? static_cast<ExprBuilder &>(*ExplicitObject)
+ : LangOpts.HLSL ? static_cast<ExprBuilder &>(*This)
+ : static_cast<ExprBuilder &>(*DerefThis))
+ .build(*this, Loc);
StmtResult Return = BuildReturnStmt(Loc, ThisExpr);
if (Return.isInvalid())
Invalid = true;
@@ -14958,7 +15225,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules.
QualType ArgType = Context.getTypeDeclType(ClassDecl);
- ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
+ ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr,
+ ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ArgType, AS);
@@ -15150,7 +15418,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
SmallVector<Stmt*, 8> Statements;
// The parameter for the "other" object, which we are move from.
- ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
+ ParmVarDecl *Other = MoveAssignOperator->getNonObjectParameter(0);
QualType OtherRefType =
Other->getType()->castAs<RValueReferenceType>()->getPointeeType();
@@ -15164,8 +15432,23 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Cast to rvalue.
MoveCastBuilder MoveOther(OtherRef);
- // Builds the "this" pointer.
- ThisBuilder This;
+ // Builds the function object parameter.
+ std::optional<ThisBuilder> This;
+ std::optional<DerefBuilder> DerefThis;
+ std::optional<RefBuilder> ExplicitObject;
+ QualType ObjectType;
+ if (MoveAssignOperator->isExplicitObjectMemberFunction()) {
+ ObjectType = MoveAssignOperator->getParamDecl(0)->getType();
+ if (ObjectType->isReferenceType())
+ ObjectType = ObjectType->getPointeeType();
+ ExplicitObject.emplace(MoveAssignOperator->getParamDecl(0), ObjectType);
+ } else {
+ ObjectType = getCurrentThisType();
+ This.emplace();
+ DerefThis.emplace(*This);
+ }
+ ExprBuilder &ObjectParameter =
+ ExplicitObject ? *ExplicitObject : static_cast<ExprBuilder &>(*This);
// Assign base classes.
bool Invalid = false;
@@ -15193,14 +15476,13 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// appropriately-qualified base type.
CastBuilder From(OtherRef, BaseType, VK_XValue, BasePath);
- // Dereference "this".
- DerefBuilder DerefThis(This);
-
// Implicitly cast "this" to the appropriately-qualified base type.
- CastBuilder To(DerefThis,
- Context.getQualifiedType(
- BaseType, MoveAssignOperator->getMethodQualifiers()),
- VK_LValue, BasePath);
+ // Dereference "this".
+ CastBuilder To(
+ ExplicitObject ? static_cast<ExprBuilder &>(*ExplicitObject)
+ : static_cast<ExprBuilder &>(*DerefThis),
+ Context.getQualifiedType(BaseType, ObjectType.getQualifiers()),
+ VK_LValue, BasePath);
// Build the move.
StmtResult Move = buildSingleCopyAssign(*this, Loc, BaseType,
@@ -15265,8 +15547,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MemberLookup.resolveKind();
MemberBuilder From(MoveOther, OtherRefType,
/*IsArrow=*/false, MemberLookup);
- MemberBuilder To(This, getCurrentThisType(),
- /*IsArrow=*/true, MemberLookup);
+ MemberBuilder To(ObjectParameter, ObjectType, /*IsArrow=*/!ExplicitObject,
+ MemberLookup);
assert(!From.build(*this, Loc)->isLValue() && // could be xvalue or prvalue
"Member reference with rvalue base must be rvalue except for reference "
@@ -15288,10 +15570,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
- ExprResult ThisObj =
- CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
+ Expr *ThisExpr =
+ (ExplicitObject ? static_cast<ExprBuilder &>(*ExplicitObject)
+ : static_cast<ExprBuilder &>(*DerefThis))
+ .build(*this, Loc);
- StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
+ StmtResult Return = BuildReturnStmt(Loc, ThisExpr);
if (Return.isInvalid())
Invalid = true;
else
@@ -15331,7 +15615,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
- ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
+ ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr,
+ ArgType, nullptr);
bool Const = ClassDecl->implicitCopyConstructorHasConstParam();
if (Const)
ArgType = ArgType.withConst();
@@ -15476,7 +15761,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
- ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
+ ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr,
+ ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ClassType, AS);
@@ -15610,7 +15896,9 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
CXXRecordDecl *Lambda = Conv->getParent();
FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
FunctionDecl *Invoker =
- CallOp->isStatic() ? CallOp : Lambda->getLambdaStaticInvoker(CC);
+ CallOp->hasCXXExplicitFunctionObjectParameter() || CallOp->isStatic()
+ ? CallOp
+ : Lambda->getLambdaStaticInvoker(CC);
if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) {
CallOp = InstantiateFunctionDeclaration(
@@ -15733,17 +16021,12 @@ static bool hasOneRealArgument(MultiExprArg Args) {
return false;
}
-ExprResult
-Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
- NamedDecl *FoundDecl,
- CXXConstructorDecl *Constructor,
- MultiExprArg ExprArgs,
- bool HadMultipleCandidates,
- bool IsListInitialization,
- bool IsStdInitListInitialization,
- bool RequiresZeroInit,
- unsigned ConstructKind,
- SourceRange ParenRange) {
+ExprResult Sema::BuildCXXConstructExpr(
+ SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl,
+ CXXConstructorDecl *Constructor, MultiExprArg ExprArgs,
+ bool HadMultipleCandidates, bool IsListInitialization,
+ bool IsStdInitListInitialization, bool RequiresZeroInit,
+ CXXConstructionKind ConstructKind, SourceRange ParenRange) {
bool Elidable = false;
// C++0x [class.copy]p34:
@@ -15756,7 +16039,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// with the same cv-unqualified type, the copy/move operation
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
- if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor &&
+ if (ConstructKind == CXXConstructionKind::Complete && Constructor &&
// FIXME: Converting constructors should also be accepted.
// But to fix this, the logic that digs down into a CXXConstructExpr
// to find the source object needs to handle it.
@@ -15780,18 +16063,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
ConstructKind, ParenRange);
}
-ExprResult
-Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
- NamedDecl *FoundDecl,
- CXXConstructorDecl *Constructor,
- bool Elidable,
- MultiExprArg ExprArgs,
- bool HadMultipleCandidates,
- bool IsListInitialization,
- bool IsStdInitListInitialization,
- bool RequiresZeroInit,
- unsigned ConstructKind,
- SourceRange ParenRange) {
+ExprResult Sema::BuildCXXConstructExpr(
+ SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl,
+ CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs,
+ bool HadMultipleCandidates, bool IsListInitialization,
+ bool IsStdInitListInitialization, bool RequiresZeroInit,
+ CXXConstructionKind ConstructKind, SourceRange ParenRange) {
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
// The only way to get here is if we did overlaod resolution to find the
@@ -15809,17 +16086,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
-ExprResult
-Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
- CXXConstructorDecl *Constructor,
- bool Elidable,
- MultiExprArg ExprArgs,
- bool HadMultipleCandidates,
- bool IsListInitialization,
- bool IsStdInitListInitialization,
- bool RequiresZeroInit,
- unsigned ConstructKind,
- SourceRange ParenRange) {
+ExprResult Sema::BuildCXXConstructExpr(
+ SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs,
+ bool HadMultipleCandidates, bool IsListInitialization,
+ bool IsStdInitListInitialization, bool RequiresZeroInit,
+ CXXConstructionKind ConstructKind, SourceRange ParenRange) {
assert(declaresSameEntity(
Constructor->getParent(),
DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) &&
@@ -15833,8 +16105,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
HadMultipleCandidates, IsListInitialization,
IsStdInitListInitialization, RequiresZeroInit,
- static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
- ParenRange),
+ static_cast<CXXConstructionKind>(ConstructKind), ParenRange),
Constructor);
}
@@ -16216,8 +16487,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// [...] Operator functions cannot have more or fewer parameters
// than the number required for the corresponding operator, as
// described in the rest of this subclause.
- unsigned NumParams = FnDecl->getNumParams()
- + (isa<CXXMethodDecl>(FnDecl)? 1 : 0);
+ unsigned NumParams = FnDecl->getNumParams() +
+ (isa<CXXMethodDecl>(FnDecl) &&
+ !FnDecl->hasCXXExplicitFunctionObjectParameter()
+ ? 1
+ : 0);
if (Op != OO_Call && Op != OO_Subscript &&
((NumParams == 1 && !CanBeUnaryOperator) ||
(NumParams == 2 && !CanBeBinaryOperator) || (NumParams < 1) ||
@@ -16524,11 +16798,11 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
assert(Lit->isUnevaluated() && "Unexpected string literal kind");
StringRef Lang = Lit->getString();
- LinkageSpecDecl::LanguageIDs Language;
+ LinkageSpecLanguageIDs Language;
if (Lang == "C")
- Language = LinkageSpecDecl::lang_c;
+ Language = LinkageSpecLanguageIDs::C;
else if (Lang == "C++")
- Language = LinkageSpecDecl::lang_cxx;
+ Language = LinkageSpecLanguageIDs::CXX;
else {
Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown)
<< LangStr->getSourceRange();
@@ -16551,8 +16825,7 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
/// If the declaration is already in global module fragment, we don't
/// need to attach it again.
if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) {
- Module *GlobalModule = PushImplicitGlobalModuleFragment(
- ExternLoc, /*IsExported=*/D->isInExportDeclContext());
+ Module *GlobalModule = PushImplicitGlobalModuleFragment(ExternLoc);
D->setLocalOwningModule(GlobalModule);
}
@@ -16799,10 +17072,74 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
AssertMessageExpr, RParenLoc, false);
}
+static void WriteCharTypePrefix(BuiltinType::Kind BTK, llvm::raw_ostream &OS) {
+ switch (BTK) {
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ break;
+ case BuiltinType::Char8:
+ OS << "u8";
+ break;
+ case BuiltinType::Char16:
+ OS << 'u';
+ break;
+ case BuiltinType::Char32:
+ OS << 'U';
+ break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ OS << 'L';
+ break;
+ default:
+ llvm_unreachable("Non-character type");
+ }
+}
+
+/// Convert character's value, interpreted as a code unit, to a string.
+/// The value needs to be zero-extended to 32-bits.
+/// FIXME: This assumes Unicode literal encodings
+static void WriteCharValueForDiagnostic(uint32_t Value, const BuiltinType *BTy,
+ unsigned TyWidth,
+ SmallVectorImpl<char> &Str) {
+ char Arr[UNI_MAX_UTF8_BYTES_PER_CODE_POINT];
+ char *Ptr = Arr;
+ BuiltinType::Kind K = BTy->getKind();
+ llvm::raw_svector_ostream OS(Str);
+
+ // This should catch Char_S, Char_U, Char8, and use of escaped characters in
+ // other types.
+ if (K == BuiltinType::Char_S || K == BuiltinType::Char_U ||
+ K == BuiltinType::Char8 || Value <= 0x7F) {
+ StringRef Escaped = escapeCStyle<EscapeChar::Single>(Value);
+ if (!Escaped.empty())
+ EscapeStringForDiagnostic(Escaped, Str);
+ else
+ OS << static_cast<char>(Value);
+ return;
+ }
+
+ switch (K) {
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: {
+ if (llvm::ConvertCodePointToUTF8(Value, Ptr))
+ EscapeStringForDiagnostic(StringRef(Arr, Ptr - Arr), Str);
+ else
+ OS << "\\x"
+ << llvm::format_hex_no_prefix(Value, TyWidth / 4, /*Upper=*/true);
+ break;
+ }
+ default:
+ llvm_unreachable("Non-character type is passed");
+ }
+}
+
/// Convert \V to a string we can present to the user in a diagnostic
/// \T is the type of the expression that has been evaluated into \V
static bool ConvertAPValueToString(const APValue &V, QualType T,
- SmallVectorImpl<char> &Str) {
+ SmallVectorImpl<char> &Str,
+ ASTContext &Context) {
if (!V.hasValue())
return false;
@@ -16817,13 +17154,38 @@ static bool ConvertAPValueToString(const APValue &V, QualType T,
"Bool type, but value is not 0 or 1");
llvm::raw_svector_ostream OS(Str);
OS << (BoolValue ? "true" : "false");
- } else if (T->isCharType()) {
+ } else {
+ llvm::raw_svector_ostream OS(Str);
// Same is true for chars.
- Str.push_back('\'');
- Str.push_back(V.getInt().getExtValue());
- Str.push_back('\'');
- } else
+ // We want to print the character representation for textual types
+ const auto *BTy = T->getAs<BuiltinType>();
+ if (BTy) {
+ switch (BTy->getKind()) {
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::Char8:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: {
+ unsigned TyWidth = Context.getIntWidth(T);
+ assert(8 <= TyWidth && TyWidth <= 32 && "Unexpected integer width");
+ uint32_t CodeUnit = static_cast<uint32_t>(V.getInt().getZExtValue());
+ WriteCharTypePrefix(BTy->getKind(), OS);
+ OS << '\'';
+ WriteCharValueForDiagnostic(CodeUnit, BTy, TyWidth, Str);
+ OS << "' (0x"
+ << llvm::format_hex_no_prefix(CodeUnit, /*Width=*/2,
+ /*Upper=*/true)
+ << ", " << V.getInt() << ')';
+ return true;
+ }
+ default:
+ break;
+ }
+ }
V.getInt().toString(Str);
+ }
break;
@@ -16883,10 +17245,10 @@ static bool UsefulToPrintExpr(const Expr *E) {
if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E))
return UsefulToPrintExpr(UnaryOp->getSubExpr());
- // Ignore nested binary operators. This could be a FIXME for improvements
- // to the diagnostics in the future.
- if (isa<BinaryOperator>(E))
- return false;
+ // Only print nested arithmetic operators.
+ if (const auto *BO = dyn_cast<BinaryOperator>(E))
+ return (BO->isShiftOp() || BO->isAdditiveOp() || BO->isMultiplicativeOp() ||
+ BO->isBitwiseOp());
return true;
}
@@ -16920,8 +17282,9 @@ void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
Side->EvaluateAsRValue(DiagSide[I].Result, Context, true);
- DiagSide[I].Print = ConvertAPValueToString(
- DiagSide[I].Result.Val, Side->getType(), DiagSide[I].ValueString);
+ DiagSide[I].Print =
+ ConvertAPValueToString(DiagSide[I].Result.Val, Side->getType(),
+ DiagSide[I].ValueString, Context);
}
if (DiagSide[0].Print && DiagSide[1].Print) {
Diag(Op->getExprLoc(), diag::note_expr_evaluates_to)
@@ -16955,33 +17318,15 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
auto FindMember = [&](StringRef Member, bool &Empty,
bool Diag = false) -> std::optional<LookupResult> {
- QualType ObjectType = Message->getType();
- Expr::Classification ObjectClassification =
- Message->Classify(getASTContext());
-
DeclarationName DN = PP.getIdentifierInfo(Member);
LookupResult MemberLookup(*this, DN, Loc, Sema::LookupMemberName);
LookupQualifiedName(MemberLookup, RD);
Empty = MemberLookup.empty();
OverloadCandidateSet Candidates(MemberLookup.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
- for (NamedDecl *D : MemberLookup) {
- AddMethodCandidate(DeclAccessPair::make(D, D->getAccess()), ObjectType,
- ObjectClassification, /*Args=*/{}, Candidates);
- }
- OverloadCandidateSet::iterator Best;
- switch (Candidates.BestViableFunction(*this, Loc, Best)) {
- case OR_Success:
- return std::move(MemberLookup);
- default:
- if (Diag)
- Candidates.NoteCandidates(
- PartialDiagnosticAt(
- Loc, PDiag(diag::err_static_assert_invalid_mem_fn_ret_ty)
- << (Member == "data")),
- *this, OCD_AllCandidates, /*Args=*/{});
- }
- return std::nullopt;
+ if (MemberLookup.empty())
+ return std::nullopt;
+ return std::move(MemberLookup);
};
bool SizeNotFound, DataNotFound;
@@ -17985,6 +18330,16 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
}
}
+ // SME attributes must match when overriding a function declaration.
+ if (IsInvalidSMECallConversion(
+ Old->getType(), New->getType(),
+ AArch64SMECallConversionKind::MayAddPreservesZA)) {
+ Diag(New->getLocation(), diag::err_conflicting_overriding_attributes)
+ << New << New->getType() << Old->getType();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
// Virtual overrides must have the same code_seg.
const auto *OldCSA = Old->getAttr<CodeSegAttr>();
const auto *NewCSA = New->getAttr<CodeSegAttr>();
@@ -18015,6 +18370,20 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
return true;
}
+bool Sema::CheckExplicitObjectOverride(CXXMethodDecl *New,
+ const CXXMethodDecl *Old) {
+ // CWG2553
+ // A virtual function shall not be an explicit object member function.
+ if (!New->isExplicitObjectMemberFunction())
+ return true;
+ Diag(New->getParamDecl(0)->getBeginLoc(),
+ diag::err_explicit_object_parameter_nonmember)
+ << New->getSourceRange() << /*virtual*/ 1 << /*IsLambda*/ false;
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ New->setInvalidDecl();
+ return false;
+}
+
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
QualType NewTy = New->getType()->castAs<FunctionType>()->getReturnType();