diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 775 |
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(); |
