diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp | 2943 |
1 files changed, 2059 insertions, 884 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp index ac01beb1bf93..df5bd55e7c28 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp @@ -17,7 +17,10 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ComparisonCategories.h" +#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" @@ -26,23 +29,30 @@ #include "clang/AST/TypeOrdering.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" +#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/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/SaveAndRestore.h" #include <map> +#include <optional> #include <set> using namespace clang; @@ -77,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; } @@ -85,7 +96,11 @@ bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) { /// determine whether this declaration can be used in the default /// argument expression. bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { - const NamedDecl *Decl = DRE->getDecl(); + const ValueDecl *Decl = dyn_cast<ValueDecl>(DRE->getDecl()); + + if (!isa<VarDecl, BindingDecl>(Decl)) + return false; + if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) { // C++ [dcl.fct.default]p9: // [...] parameters of a function shall not be used in default @@ -99,7 +114,7 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { return S.Diag(DRE->getBeginLoc(), diag::err_param_default_argument_references_param) << Param->getDeclName() << DefaultArg->getSourceRange(); - } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) { + } else if (auto *VD = Decl->getPotentiallyDecomposedVarDecl()) { // C++ [dcl.fct.default]p7: // Local variables shall not be used in default argument // expressions. @@ -109,14 +124,14 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { // expression in a default argument. // // C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346): - // Note: A local variable cannot be odr-used (6.3) in a default argument. + // Note: A local variable cannot be odr-used (6.3) in a default + // argument. // - if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse()) + if (VD->isLocalVarDecl() && !DRE->isNonOdrUse()) return S.Diag(DRE->getBeginLoc(), diag::err_param_default_argument_references_local) - << VDecl->getDeclName() << DefaultArg->getSourceRange(); + << Decl << DefaultArg->getSourceRange(); } - return false; } @@ -146,13 +161,20 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr( } bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) { - // C++11 [expr.lambda.prim]p13: - // A lambda-expression appearing in a default argument shall not - // implicitly or explicitly capture any entity. - if (Lambda->capture_begin() == Lambda->capture_end()) - return false; - - return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg); + // [expr.prim.lambda.capture]p9 + // a lambda-expression appearing in a default argument cannot implicitly or + // explicitly capture any local entity. Such a lambda-expression can still + // have an init-capture if any full-expression in its initializer satisfies + // the constraints of an expression appearing in a default argument. + bool Invalid = false; + for (const LambdaCapture &LC : Lambda->captures()) { + if (!Lambda->isInitCapture(&LC)) + return S.Diag(LC.getLocation(), diag::err_lambda_capture_default_arg); + // Init captures are always VarDecl. + auto *D = cast<VarDecl>(LC.getCapturedVar()); + Invalid |= Visit(D->getInit()); + } + return Invalid; } } // namespace @@ -312,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 @@ -343,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); } @@ -372,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 @@ -435,7 +457,7 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { } static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) { - return std::any_of(FD->param_begin(), FD->param_end(), [](ParmVarDecl *P) { + return llvm::any_of(FD->parameters(), [](ParmVarDecl *P) { return P->hasDefaultArg() && !P->hasInheritedDefaultArg(); }); } @@ -706,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) { @@ -743,11 +771,16 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // C++17 [dcl.dcl]/8: // The decl-specifier-seq shall contain only the type-specifier auto // and cv-qualifiers. - // C++2a [dcl.dcl]/8: + // C++20 [dcl.dcl]/8: // If decl-specifier-seq contains any decl-specifier other than static, // thread_local, auto, or cv-qualifiers, the program is ill-formed. + // C++23 [dcl.pre]/6: + // Each decl-specifier in the decl-specifier-seq shall be static, + // thread_local, auto (9.2.9.6 [dcl.spec.auto]), or a cv-qualifier. auto &DS = D.getDeclSpec(); { + // Note: While constrained-auto needs to be checked, we do so separately so + // we can emit a better diagnostic. SmallVector<StringRef, 8> BadSpecifiers; SmallVector<SourceLocation, 8> BadSpecifierLocs; SmallVector<StringRef, 8> CPlusPlus20Specifiers; @@ -774,6 +807,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, BadSpecifiers.push_back("inline"); BadSpecifierLocs.push_back(DS.getInlineSpecLoc()); } + if (!BadSpecifiers.empty()) { auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec); Err << (int)BadSpecifiers.size() @@ -805,7 +839,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Diag(DS.getVolatileSpecLoc(), diag::warn_deprecated_volatile_structured_binding); - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D); QualType R = TInfo->getType(); if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, @@ -834,6 +868,20 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, D.setInvalidType(); } + // Constrained auto is prohibited by [decl.pre]p6, so check that here. + if (DS.isConstrainedAuto()) { + TemplateIdAnnotation *TemplRep = DS.getRepAsTemplateId(); + assert(TemplRep->Kind == TNK_Concept_template && + "No other template kind should be possible for a constrained auto"); + + SourceRange TemplRange{TemplRep->TemplateNameLoc, + TemplRep->RAngleLoc.isValid() + ? TemplRep->RAngleLoc + : TemplRep->TemplateNameLoc}; + Diag(TemplRep->TemplateNameLoc, diag::err_decomp_decl_constraint) + << TemplRange << FixItHint::CreateRemoval(TemplRange); + } + // Build the BindingDecls. SmallVector<BindingDecl*, 8> Bindings; @@ -841,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, @@ -854,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() @@ -866,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); } @@ -983,9 +1048,9 @@ static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, for (auto &Arg : Args.arguments()) { if (!First) OS << ", "; - Arg.getArgument().print( - PrintingPolicy, OS, - TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); + Arg.getArgument().print(PrintingPolicy, OS, + TemplateParameterList::shouldIncludeTypeForArgument( + PrintingPolicy, Params, I)); First = false; I++; } @@ -1228,14 +1293,15 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; - E = S.BuildCallExpr(nullptr, E.get(), Loc, None, Loc); + E = S.BuildCallExpr(nullptr, E.get(), Loc, std::nullopt, Loc); } else { // Otherwise, the initializer is get<i-1>(e), where get is looked up // 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); @@ -1383,9 +1449,8 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, DecompType.getQualifiers()); auto DiagnoseBadNumberOfBindings = [&]() -> bool { - unsigned NumFields = - std::count_if(RD->field_begin(), RD->field_end(), - [](FieldDecl *FD) { return !FD->isUnnamedBitfield(); }); + unsigned NumFields = llvm::count_if( + RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitfield(); }); assert(Bindings.size() != NumFields); S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) << DecompType << (unsigned)Bindings.size() << NumFields << NumFields @@ -1687,6 +1752,7 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, e = FT->param_type_end(); i != e; ++i, ++ArgIndex) { const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); + assert(PD && "null in a parameter list"); SourceLocation ParamLoc = PD->getLocation(); if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1, @@ -1715,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!"); } } @@ -1892,16 +1961,26 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, if (VD->isStaticLocal()) { if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag(VD->getLocation(), - diag::err_constexpr_local_var_static) - << isa<CXXConstructorDecl>(Dcl) - << (VD->getTLSKind() == VarDecl::TLS_Dynamic); + SemaRef.getLangOpts().CPlusPlus23 + ? diag::warn_cxx20_compat_constexpr_var + : diag::ext_constexpr_static_var) + << isa<CXXConstructorDecl>(Dcl) + << (VD->getTLSKind() == VarDecl::TLS_Dynamic); + } else if (!SemaRef.getLangOpts().CPlusPlus23) { + return false; } - return false; } - if (CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), - diag::err_constexpr_local_var_non_literal_type, - isa<CXXConstructorDecl>(Dcl))) + if (SemaRef.LangOpts.CPlusPlus23) { + CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), + diag::warn_cxx20_compat_constexpr_var, + isa<CXXConstructorDecl>(Dcl), + /*variable of non-literal type*/ 2); + } else if (CheckLiteralType( + SemaRef, Kind, VD->getLocation(), VD->getType(), + diag::err_constexpr_local_var_non_literal_type, + isa<CXXConstructorDecl>(Dcl))) { return false; + } if (!VD->getType()->isDependentType() && !VD->hasInit() && !VD->isCXXForRangeDecl()) { if (Kind == Sema::CheckConstexprKind::Diagnose) { @@ -2021,6 +2100,7 @@ static bool CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, SmallVectorImpl<SourceLocation> &ReturnStmts, SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc, + SourceLocation &Cxx2bLoc, Sema::CheckConstexprKind Kind) { // - its function-body shall be [...] a compound-statement that contains only switch (S->getStmtClass()) { @@ -2050,6 +2130,13 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, ReturnStmts.push_back(S->getBeginLoc()); return true; + case Stmt::AttributedStmtClass: + // Attributes on a statement don't affect its formal kind and hence don't + // affect its validity in a constexpr function. + return CheckConstexprFunctionStmt( + SemaRef, Dcl, cast<AttributedStmt>(S)->getSubStmt(), ReturnStmts, + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind); + case Stmt::CompoundStmtClass: { // C++1y allows compound-statements. if (!Cxx1yLoc.isValid()) @@ -2058,17 +2145,12 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, CompoundStmt *CompStmt = cast<CompoundStmt>(S); for (auto *BodyIt : CompStmt->body()) { if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; } return true; } - case Stmt::AttributedStmtClass: - if (!Cxx1yLoc.isValid()) - Cxx1yLoc = S->getBeginLoc(); - return true; - case Stmt::IfStmtClass: { // C++1y allows if-statements. if (!Cxx1yLoc.isValid()) @@ -2076,11 +2158,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, IfStmt *If = cast<IfStmt>(S); if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; if (If->getElse() && !CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; return true; } @@ -2096,11 +2178,12 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, break; if (!Cxx1yLoc.isValid()) Cxx1yLoc = S->getBeginLoc(); - for (Stmt *SubStmt : S->children()) + for (Stmt *SubStmt : S->children()) { if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; + } return true; case Stmt::SwitchStmtClass: @@ -2111,11 +2194,24 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, // mutation, we can reasonably allow them in C++11 as an extension. if (!Cxx1yLoc.isValid()) Cxx1yLoc = S->getBeginLoc(); - for (Stmt *SubStmt : S->children()) + for (Stmt *SubStmt : S->children()) { + if (SubStmt && + !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) + return false; + } + return true; + + case Stmt::LabelStmtClass: + case Stmt::GotoStmtClass: + if (Cxx2bLoc.isInvalid()) + Cxx2bLoc = S->getBeginLoc(); + for (Stmt *SubStmt : S->children()) { if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; + } return true; case Stmt::GCCAsmStmtClass: @@ -2127,7 +2223,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, for (Stmt *SubStmt : S->children()) { if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; } return true; @@ -2135,9 +2231,9 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, case Stmt::CXXCatchStmtClass: // Do not bother checking the language mode (already covered by the // try block check). - if (!CheckConstexprFunctionStmt(SemaRef, Dcl, - cast<CXXCatchStmt>(S)->getHandlerBlock(), - ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind)) + if (!CheckConstexprFunctionStmt( + SemaRef, Dcl, cast<CXXCatchStmt>(S)->getHandlerBlock(), ReturnStmts, + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; return true; @@ -2202,20 +2298,27 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, // // Note that walking the children here is enough to properly check for // CompoundStmt and CXXTryStmt body. - SourceLocation Cxx1yLoc, Cxx2aLoc; + SourceLocation Cxx1yLoc, Cxx2aLoc, Cxx2bLoc; for (Stmt *SubStmt : Body->children()) { if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc, Kind)) + Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind)) return false; } if (Kind == Sema::CheckConstexprKind::CheckValid) { // If this is only valid as an extension, report that we don't satisfy the // constraints of the current language. - if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) || + if ((Cxx2bLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus23) || + (Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) || (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) return false; + } else if (Cxx2bLoc.isValid()) { + SemaRef.Diag(Cxx2bLoc, + SemaRef.getLangOpts().CPlusPlus23 + ? diag::warn_cxx20_compat_constexpr_body_invalid_stmt + : diag::ext_constexpr_body_invalid_stmt_cxx23) + << isa<CXXConstructorDecl>(Dcl); } else if (Cxx2aLoc.isValid()) { SemaRef.Diag(Cxx2aLoc, SemaRef.getLangOpts().CPlusPlus20 @@ -2357,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 @@ -2367,6 +2471,117 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, return true; } +bool Sema::CheckImmediateEscalatingFunctionDefinition( + FunctionDecl *FD, const sema::FunctionScopeInfo *FSI) { + if (!getLangOpts().CPlusPlus20 || !FD->isImmediateEscalating()) + return true; + FD->setBodyContainsImmediateEscalatingExpressions( + FSI->FoundImmediateEscalatingExpression); + if (FSI->FoundImmediateEscalatingExpression) { + auto it = UndefinedButUsed.find(FD->getCanonicalDecl()); + if (it != UndefinedButUsed.end()) { + Diag(it->second, diag::err_immediate_function_used_before_definition) + << it->first; + Diag(FD->getLocation(), diag::note_defined_here) << FD; + if (FD->isImmediateFunction() && !FD->isConsteval()) + DiagnoseImmediateEscalatingReason(FD); + return false; + } + } + return true; +} + +void Sema::DiagnoseImmediateEscalatingReason(FunctionDecl *FD) { + assert(FD->isImmediateEscalating() && !FD->isConsteval() && + "expected an immediate function"); + assert(FD->hasBody() && "expected the function to have a body"); + struct ImmediateEscalatingExpressionsVisitor + : public RecursiveASTVisitor<ImmediateEscalatingExpressionsVisitor> { + + using Base = RecursiveASTVisitor<ImmediateEscalatingExpressionsVisitor>; + Sema &SemaRef; + + const FunctionDecl *ImmediateFn; + bool ImmediateFnIsConstructor; + CXXConstructorDecl *CurrentConstructor = nullptr; + CXXCtorInitializer *CurrentInit = nullptr; + + ImmediateEscalatingExpressionsVisitor(Sema &SemaRef, FunctionDecl *FD) + : SemaRef(SemaRef), ImmediateFn(FD), + ImmediateFnIsConstructor(isa<CXXConstructorDecl>(FD)) {} + + bool shouldVisitImplicitCode() const { return true; } + bool shouldVisitLambdaBody() const { return false; } + + void Diag(const Expr *E, const FunctionDecl *Fn, bool IsCall) { + SourceLocation Loc = E->getBeginLoc(); + SourceRange Range = E->getSourceRange(); + if (CurrentConstructor && CurrentInit) { + Loc = CurrentConstructor->getLocation(); + 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 + << (InitializedField != nullptr) + << (CurrentInit && !CurrentInit->isWritten()) + << InitializedField << Range; + } + bool TraverseCallExpr(CallExpr *E) { + if (const auto *DR = + dyn_cast<DeclRefExpr>(E->getCallee()->IgnoreImplicit()); + DR && DR->isImmediateEscalating()) { + Diag(E, E->getDirectCallee(), /*IsCall=*/true); + return false; + } + + for (Expr *A : E->arguments()) + if (!getDerived().TraverseStmt(A)) + return false; + + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (const auto *ReferencedFn = dyn_cast<FunctionDecl>(E->getDecl()); + ReferencedFn && E->isImmediateEscalating()) { + Diag(E, ReferencedFn, /*IsCall=*/false); + return false; + } + + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + CXXConstructorDecl *D = E->getConstructor(); + if (E->isImmediateEscalating()) { + Diag(E, D, /*IsCall=*/true); + return false; + } + return true; + } + + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + llvm::SaveAndRestore RAII(CurrentInit, Init); + return Base::TraverseConstructorInitializer(Init); + } + + bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctr) { + llvm::SaveAndRestore RAII(CurrentConstructor, Ctr); + return Base::TraverseCXXConstructorDecl(Ctr); + } + + bool TraverseType(QualType T) { return true; } + bool VisitBlockExpr(BlockExpr *T) { return true; } + + } Visitor(*this, FD); + Visitor.TraverseDecl(FD); +} + /// Get the class that is directly named by the current context. This is the /// class for which an unqualified-id in this scope could name a constructor /// or destructor. @@ -2467,6 +2682,11 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, bool Virtual, AccessSpecifier Access, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) { + // In HLSL, unspecified class access is public rather than private. + if (getLangOpts().HLSL && Class->getTagKind() == TagTypeKind::Class && + Access == AS_none) + Access = AS_public; + QualType BaseType = TInfo->getType(); if (BaseType->containsErrors()) { // Already emitted a diagnostic when parsing the error type. @@ -2516,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. @@ -2535,7 +2755,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } // For the MS ABI, propagate DLL attributes to base class templates. - if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + if (Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isPS()) { if (Attr *ClassAttr = getDLLAttr(Class)) { if (auto *BaseTemplate = dyn_cast_or_null<ClassTemplateSpecializationDecl>( BaseType->getAsCXXRecordDecl())) { @@ -2603,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 @@ -2613,12 +2834,11 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, /// example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. -BaseResult -Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, - ParsedAttributes &Attributes, - bool Virtual, AccessSpecifier Access, - ParsedType basetype, SourceLocation BaseLoc, - SourceLocation EllipsisLoc) { +BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, + const ParsedAttributesView &Attributes, + bool Virtual, AccessSpecifier Access, + ParsedType basetype, SourceLocation BaseLoc, + SourceLocation EllipsisLoc) { if (!classdecl) return true; @@ -2635,10 +2855,12 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, for (const ParsedAttr &AL : Attributes) { if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) continue; - Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute - ? (unsigned)diag::warn_unknown_attribute_ignored - : (unsigned)diag::err_base_specifier_attribute) - << AL << AL.getRange(); + if (AL.getKind() == ParsedAttr::UnknownAttribute) + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL << AL.getRange(); + else + Diag(AL.getLoc(), diag::err_base_specifier_attribute) + << AL << AL.isRegularKeywordAttribute() << AL.getRange(); } TypeSourceInfo *TInfo = nullptr; @@ -2727,6 +2949,8 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, KnownBase = Bases[idx]; Bases[NumGoodBases++] = Bases[idx]; + if (NewBaseType->isDependentType()) + continue; // Note this base's direct & indirect bases, if there could be ambiguity. if (Bases.size() > 1) NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType); @@ -3044,7 +3268,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) { return; if (MD && !MD->isVirtual()) { - // If we have a non-virtual method, check if if hides a virtual method. + // If we have a non-virtual method, check if it hides a virtual method. // (In that case, it's most likely the method has the wrong type.) SmallVector<CXXMethodDecl *, 8> OverloadedMethods; FindHiddenVirtualMethods(MD, OverloadedMethods); @@ -3156,16 +3380,6 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } -static const ParsedAttr *getMSPropertyAttr(const ParsedAttributesView &list) { - ParsedAttributesView::const_iterator Itr = - llvm::find_if(list, [](const ParsedAttr &AL) { - return AL.isDeclspecPropertyAttribute(); - }); - if (Itr != list.end()) - return &*Itr; - return nullptr; -} - // Check if there is a field shadowing. void Sema::CheckShadowInheritedFields(const SourceLocation &Loc, DeclarationName FieldName, @@ -3243,7 +3457,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool isFunc = D.isDeclarationOfFunction(); const ParsedAttr *MSPropertyAttr = - getMSPropertyAttr(D.getDeclSpec().getAttributes()); + D.getDeclSpec().getAttributes().getMSPropertyAttr(); if (cast<CXXRecordDecl>(CurContext)->isInterface()) { // The Microsoft extension __interface only permits public member functions @@ -3391,6 +3605,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, return nullptr; } + if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) { + Diag(D.getIdentifierLoc(), diag::err_member_with_template_arguments) + << II + << SourceRange(D.getName().TemplateId->LAngleLoc, + D.getName().TemplateId->RAngleLoc) + << D.getName().TemplateId->LAngleLoc; + D.SetIdentifier(II, Loc); + } + if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class // definition: @@ -3492,12 +3715,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } if (VS.isOverrideSpecified()) - Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc(), - AttributeCommonInfo::AS_Keyword)); + Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc())); if (VS.isFinalSpecified()) - Member->addAttr(FinalAttr::Create( - Context, VS.getFinalLoc(), AttributeCommonInfo::AS_Keyword, - static_cast<FinalAttr::Spelling>(VS.isFinalSpelledSealed()))); + Member->addAttr(FinalAttr::Create(Context, VS.getFinalLoc(), + VS.isFinalSpelledSealed() + ? FinalAttr::Keyword_sealed + : FinalAttr::Keyword_final)); if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. @@ -3516,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); } @@ -3581,9 +3814,8 @@ namespace { llvm::SmallVector<unsigned, 4> UsedFieldIndex; // Discard the first field since it is the field decl that is being // initialized. - for (auto I = Fields.rbegin() + 1, E = Fields.rend(); I != E; ++I) { - UsedFieldIndex.push_back((*I)->getFieldIndex()); - } + for (const FieldDecl *FD : llvm::drop_begin(llvm::reverse(Fields))) + UsedFieldIndex.push_back(FD->getFieldIndex()); for (auto UsedIter = UsedFieldIndex.begin(), UsedEnd = UsedFieldIndex.end(), @@ -3728,7 +3960,7 @@ namespace { void CheckInitListExpr(InitListExpr *ILE) { InitFieldIndex.push_back(0); - for (auto Child : ILE->children()) { + for (auto *Child : ILE->children()) { if (InitListExpr *SubList = dyn_cast<InitListExpr>(Child)) { CheckInitListExpr(SubList); } else { @@ -3799,7 +4031,7 @@ namespace { Expr *Callee = E->getCallee(); if (isa<MemberExpr>(Callee)) { HandleValue(Callee, false /*AddressOf*/); - for (auto Arg : E->arguments()) + for (auto *Arg : E->arguments()) Visit(Arg); return; } @@ -3824,7 +4056,7 @@ namespace { return Inherited::VisitCXXOperatorCallExpr(E); Visit(Callee); - for (auto Arg : E->arguments()) + for (auto *Arg : E->arguments()) HandleValue(Arg->IgnoreParenImpCasts(), false /*AddressOf*/); } @@ -3897,7 +4129,7 @@ namespace { } llvm::SmallPtrSet<QualType, 4> UninitializedBaseClasses; - for (auto I : RD->bases()) + for (const auto &I : RD->bases()) UninitializedBaseClasses.insert(I.getType().getCanonicalType()); if (UninitializedFields.empty() && UninitializedBaseClasses.empty()) @@ -3975,6 +4207,21 @@ ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) { return ConstraintExpr; } +ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD, + Expr *InitExpr, + SourceLocation InitLoc) { + InitializedEntity Entity = + InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD); + InitializationKind Kind = + FD->getInClassInitStyle() == ICIS_ListInit + ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(), + InitExpr->getBeginLoc(), + InitExpr->getEndLoc()) + : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); + return Seq.Perform(*this, Entity, Kind, InitExpr); +} + /// This is invoked after parsing an in-class initializer for a /// non-static C++ class member, and after instantiating an in-class initializer /// in a class template. Such actions are deferred until the class is complete. @@ -4001,36 +4248,23 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, return; } - ExprResult Init = InitExpr; - if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { - InitializedEntity Entity = - InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD); - InitializationKind Kind = - FD->getInClassInitStyle() == ICIS_ListInit - ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(), - InitExpr->getBeginLoc(), - InitExpr->getEndLoc()) - : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc); - InitializationSequence Seq(*this, Entity, Kind, InitExpr); - Init = Seq.Perform(*this, Entity, Kind, InitExpr); + ExprResult Init = CorrectDelayedTyposInExpr(InitExpr, /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); + assert(Init.isUsable() && "Init should at least have a RecoveryExpr"); + if (!FD->getType()->isDependentType() && !Init.get()->isTypeDependent()) { + Init = ConvertMemberDefaultInitExpression(FD, Init.get(), InitLoc); + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + if (!Init.isInvalid()) + Init = ActOnFinishFullExpr(Init.get(), /*DiscarededValue=*/false); if (Init.isInvalid()) { FD->setInvalidDecl(); return; } } - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - Init = ActOnFinishFullExpr(Init.get(), InitLoc, /*DiscardedValue*/ false); - if (Init.isInvalid()) { - FD->setInvalidDecl(); - return; - } - - InitExpr = Init.get(); - - FD->setInClassInitializer(InitExpr); + FD->setInClassInitializer(Init.get()); } /// Find the direct and/or virtual base specifiers that @@ -4114,7 +4348,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, namespace { // Callback to only accept typo corrections that can be a valid C++ member -// intializer: either a non-static field member or a base class. +// initializer: either a non-static field member or a base class. class MemInitializerValidatorCCC final : public CorrectionCandidateCallback { public: explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl) @@ -4139,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. @@ -4162,7 +4437,8 @@ Sema::BuildMemInitializer(Decl *ConstructorD, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc) { - ExprResult Res = CorrectDelayedTyposInExpr(Init); + ExprResult Res = CorrectDelayedTyposInExpr(Init, /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); if (!Res.isUsable()) return true; Init = Res.get(); @@ -4214,7 +4490,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (BaseType.isNull()) return true; } else if (DS.getTypeSpecType() == TST_decltype) { - BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + BaseType = BuildDecltypeType(DS.getRepAsExpr()); } else if (DS.getTypeSpecType() == TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return true; @@ -4238,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; @@ -4258,6 +4534,25 @@ Sema::BuildMemInitializer(Decl *ConstructorD, } } + if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) { + if (auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>()) { + auto *TempSpec = cast<TemplateSpecializationType>( + UnqualifiedBase->getInjectedClassNameSpecialization()); + TemplateName TN = TempSpec->getTemplateName(); + for (auto const &Base : ClassDecl->bases()) { + auto BaseTemplate = + Base.getType()->getAs<TemplateSpecializationType>(); + if (BaseTemplate && Context.hasSameTemplateName( + BaseTemplate->getTemplateName(), TN)) { + Diag(IdLoc, diag::ext_unqualified_base_class) + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + BaseType = Base.getType(); + break; + } + } + } + } + // If no results were found, try to correct typos. TypoCorrection Corr; MemInitializerValidatorCCC CCC(ClassDecl); @@ -4304,17 +4599,14 @@ Sema::BuildMemInitializer(Decl *ConstructorD, } if (BaseType.isNull()) { - BaseType = Context.getTypeDeclType(TyD); + BaseType = getElaboratedType(ElaboratedTypeKeyword::None, SS, + Context.getTypeDeclType(TyD)); MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false); - if (SS.isSet()) { - BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(), - BaseType); - TInfo = Context.CreateTypeSourceInfo(BaseType); - ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>(); - TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); - TL.setElaboratedKeywordLoc(SourceLocation()); - TL.setQualifierLoc(SS.getWithLocInContext(Context)); - } + TInfo = Context.CreateTypeSourceInfo(BaseType); + ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>(); + TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); + TL.setElaboratedKeywordLoc(SourceLocation()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); } } @@ -4375,18 +4667,25 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, InitializationSequence InitSeq(*this, MemberEntity, Kind, Args); ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, nullptr); - if (MemberInit.isInvalid()) - return true; - - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - MemberInit = ActOnFinishFullExpr(MemberInit.get(), InitRange.getBegin(), - /*DiscardedValue*/ false); - if (MemberInit.isInvalid()) - return true; - - Init = MemberInit.get(); + if (!MemberInit.isInvalid()) { + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + MemberInit = ActOnFinishFullExpr(MemberInit.get(), InitRange.getBegin(), + /*DiscardedValue*/ false); + } + + if (MemberInit.isInvalid()) { + // Args were sensible expressions but we couldn't initialize the member + // from them. Preserve them in a RecoveryExpr instead. + Init = CreateRecoveryExpr(InitRange.getBegin(), InitRange.getEnd(), Args, + Member->getType()) + .get(); + if (!Init) + return true; + } else { + Init = MemberInit.get(); + } } if (DirectMember) { @@ -4403,10 +4702,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl) { - SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); + SourceLocation NameLoc = TInfo->getTypeLoc().getSourceRange().getBegin(); if (!LangOpts.CPlusPlus11) return Diag(NameLoc, diag::err_delegating_ctor) - << TInfo->getTypeLoc().getLocalSourceRange(); + << TInfo->getTypeLoc().getSourceRange(); Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor); bool InitList = true; @@ -4428,29 +4727,35 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, Args, nullptr); - if (DelegationInit.isInvalid()) - return true; - - assert(cast<CXXConstructExpr>(DelegationInit.get())->getConstructor() && - "Delegating constructor with no target?"); + if (!DelegationInit.isInvalid()) { + assert((DelegationInit.get()->containsErrors() || + cast<CXXConstructExpr>(DelegationInit.get())->getConstructor()) && + "Delegating constructor with no target?"); - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - DelegationInit = ActOnFinishFullExpr( - DelegationInit.get(), InitRange.getBegin(), /*DiscardedValue*/ false); - if (DelegationInit.isInvalid()) - return true; + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + DelegationInit = ActOnFinishFullExpr( + DelegationInit.get(), InitRange.getBegin(), /*DiscardedValue*/ false); + } - // If we are in a dependent context, template instantiation will - // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. - // FIXME: This isn't quite ideal, since our ASTs don't capture all - // of the information that we have about the base - // initializer. However, deconstructing the ASTs is a dicey process, - // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) - DelegationInit = Init; + if (DelegationInit.isInvalid()) { + DelegationInit = + CreateRecoveryExpr(InitRange.getBegin(), InitRange.getEnd(), Args, + QualType(ClassDecl->getTypeForDecl(), 0)); + if (DelegationInit.isInvalid()) + return true; + } else { + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) + DelegationInit = Init; + } return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), DelegationInit.getAs<Expr>(), @@ -4461,12 +4766,11 @@ MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc) { - SourceLocation BaseLoc - = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); + SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getBeginLoc(); if (!BaseType->isDependentType() && !BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) - << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -4474,7 +4778,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // of that class, the mem-initializer is ill-formed. A // mem-initializer-list can initialize a base class using any // name that denotes that base class type. - bool Dependent = BaseType->isDependentType() || Init->isTypeDependent(); + + // We can store the initializers in "as-written" form and delay analysis until + // instantiation if the constructor is dependent. But not for dependent + // (broken) code in a non-template! SetCtorInitializers does not expect this. + bool Dependent = CurContext->isDependentContext() && + (BaseType->isDependentType() || Init->isTypeDependent()); SourceRange InitRange = Init->getSourceRange(); if (EllipsisLoc.isValid()) { @@ -4519,8 +4828,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Dependent = true; else return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << Context.getTypeDeclType(ClassDecl) - << BaseTInfo->getTypeLoc().getLocalSourceRange(); + << BaseType << Context.getTypeDeclType(ClassDecl) + << BaseTInfo->getTypeLoc().getSourceRange(); } } @@ -4561,26 +4870,30 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitRange.getEnd()); InitializationSequence InitSeq(*this, BaseEntity, Kind, Args); ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, nullptr); - if (BaseInit.isInvalid()) - return true; - - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - BaseInit = ActOnFinishFullExpr(BaseInit.get(), InitRange.getBegin(), - /*DiscardedValue*/ false); - if (BaseInit.isInvalid()) - return true; + if (!BaseInit.isInvalid()) { + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + BaseInit = ActOnFinishFullExpr(BaseInit.get(), InitRange.getBegin(), + /*DiscardedValue*/ false); + } - // If we are in a dependent context, template instantiation will - // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. - // FIXME: This isn't quite ideal, since our ASTs don't capture all - // of the information that we have about the base - // initializer. However, deconstructing the ASTs is a dicey process, - // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) - BaseInit = Init; + if (BaseInit.isInvalid()) { + BaseInit = CreateRecoveryExpr(InitRange.getBegin(), InitRange.getEnd(), + Args, BaseType); + if (BaseInit.isInvalid()) + return true; + } else { + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) + BaseInit = Init; + } return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), @@ -4590,10 +4903,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, } // Create a static_cast\<T&&>(expr). -static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) { - if (T.isNull()) T = E->getType(); - QualType TargetType = SemaRef.BuildReferenceType( - T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName()); +static Expr *CastForMoving(Sema &SemaRef, Expr *E) { + QualType TargetType = + SemaRef.BuildReferenceType(E->getType(), /*SpelledAsLValue*/ false, + SourceLocation(), DeclarationName()); SourceLocation ExprLoc = E->getBeginLoc(); TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo( TargetType, ExprLoc); @@ -4629,8 +4942,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, None); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); break; } @@ -4794,9 +5107,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDefault(Loc); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt); ExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, None); + InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) @@ -5350,8 +5663,7 @@ static void DiagnoseBaseOrMemInitializerOrder( return; // Sort based on the ideal order, first in the pair. - llvm::sort(CorrelatedInitOrder, - [](auto &LHS, auto &RHS) { return LHS.first < RHS.first; }); + llvm::sort(CorrelatedInitOrder, llvm::less_first()); // Introduce a new scope as SemaDiagnosticBuilder needs to be destroyed to // emit the diagnostic before we can try adding notes. @@ -5565,7 +5877,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, continue; CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl); - assert(Dtor && "No dtor found for FieldClassDecl!"); + // Dtor might still be missing, e.g because it's invalid. + if (!Dtor) + continue; CheckDestructorAccess(Field->getLocation(), Dtor, PDiag(diag::err_access_dtor_field) << Field->getDeclName() @@ -5611,7 +5925,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); - assert(Dtor && "No dtor found for BaseClassDecl!"); + // Dtor might still be missing, e.g because it's invalid. + if (!Dtor) + continue; // FIXME: caret should be on the start of the class name CheckDestructorAccess(Base.getBeginLoc(), Dtor, @@ -5648,7 +5964,9 @@ void Sema::MarkVirtualBaseDestructorsReferenced( continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); - assert(Dtor && "No dtor found for BaseClassDecl!"); + // Dtor might still be missing, e.g because it's invalid. + if (!Dtor) + continue; if (CheckDestructorAccess( ClassDecl->getLocation(), Dtor, PDiag(diag::err_access_dtor_vbase) @@ -5744,7 +6062,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { if (SO->second.size() != 1) continue; - if (!SO->second.front().Method->isPure()) + if (!SO->second.front().Method->isPureVirtual()) continue; if (!SeenPureMethods.insert(SO->second.front().Method).second) @@ -5859,6 +6177,7 @@ struct CheckAbstractUsage { if (CT != Info.AbstractType) return; // It matched; do some magic. + // FIXME: These should be at most warnings. See P0929R2, CWG1640, CWG1646. if (Sel == Sema::AbstractArrayType) { Info.S.Diag(Ctx->getLocation(), diag::err_array_of_abstract_type) << T << TL.getSourceRange(); @@ -5877,19 +6196,31 @@ void AbstractUsageInfo::CheckType(const NamedDecl *D, TypeLoc TL, } -/// Check for invalid uses of an abstract type in a method declaration. +/// Check for invalid uses of an abstract type in a function declaration. static void CheckAbstractClassUsage(AbstractUsageInfo &Info, - CXXMethodDecl *MD) { - // No need to do the check on definitions, which require that - // the return/param types be complete. - if (MD->doesThisDeclarationHaveABody()) + FunctionDecl *FD) { + // Only definitions are required to refer to complete and + // non-abstract types. + if (!FD->doesThisDeclarationHaveABody()) return; // For safety's sake, just ignore it if we don't have type source // information. This should never happen for non-implicit methods, // but... - if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) - Info.CheckType(MD, TSI->getTypeLoc(), Sema::AbstractNone); + if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) + Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractNone); +} + +/// Check for invalid uses of an abstract type in a variable0 declaration. +static void CheckAbstractClassUsage(AbstractUsageInfo &Info, + VarDecl *VD) { + // No need to do the check on definitions, which require that + // the type is complete. + if (VD->isThisDeclarationADefinition()) + return; + + Info.CheckType(VD, VD->getTypeSourceInfo()->getTypeLoc(), + Sema::AbstractVariableType); } /// Check for invalid uses of an abstract type within a class definition. @@ -5898,29 +6229,32 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, for (auto *D : RD->decls()) { if (D->isImplicit()) continue; - // Methods and method templates. - if (isa<CXXMethodDecl>(D)) { - CheckAbstractClassUsage(Info, cast<CXXMethodDecl>(D)); - } else if (isa<FunctionTemplateDecl>(D)) { - FunctionDecl *FD = cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); - CheckAbstractClassUsage(Info, cast<CXXMethodDecl>(FD)); + // Step through friends to the befriended declaration. + if (auto *FD = dyn_cast<FriendDecl>(D)) { + D = FD->getFriendDecl(); + if (!D) continue; + } + + // Functions and function templates. + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + CheckAbstractClassUsage(Info, FD); + } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) { + CheckAbstractClassUsage(Info, FTD->getTemplatedDecl()); // Fields and static variables. - } else if (isa<FieldDecl>(D)) { - FieldDecl *FD = cast<FieldDecl>(D); + } else if (auto *FD = dyn_cast<FieldDecl>(D)) { if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractFieldType); - } else if (isa<VarDecl>(D)) { - VarDecl *VD = cast<VarDecl>(D); - if (TypeSourceInfo *TSI = VD->getTypeSourceInfo()) - Info.CheckType(VD, TSI->getTypeLoc(), Sema::AbstractVariableType); + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + CheckAbstractClassUsage(Info, VD); + } else if (auto *VTD = dyn_cast<VarTemplateDecl>(D)) { + CheckAbstractClassUsage(Info, VTD->getTemplatedDecl()); // Nested classes and class templates. - } else if (isa<CXXRecordDecl>(D)) { - CheckAbstractClassUsage(Info, cast<CXXRecordDecl>(D)); - } else if (isa<ClassTemplateDecl>(D)) { - CheckAbstractClassUsage(Info, - cast<ClassTemplateDecl>(D)->getTemplatedDecl()); + } else if (auto *RD = dyn_cast<CXXRecordDecl>(D)) { + CheckAbstractClassUsage(Info, RD); + } else if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) { + CheckAbstractClassUsage(Info, CTD->getTemplatedDecl()); } } } @@ -5960,11 +6294,14 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { S.MarkVTableUsed(Class->getLocation(), Class, true); for (Decl *Member : Class->decls()) { + // Skip members that were not marked exported. + if (!Member->hasAttr<DLLExportAttr>()) + continue; + // Defined static variables that are members of an exported base // class must be marked export too. auto *VD = dyn_cast<VarDecl>(Member); - if (VD && Member->getAttr<DLLExportAttr>() && - VD->getStorageClass() == SC_Static && + if (VD && VD->getStorageClass() == SC_Static && TSK == TSK_ImplicitInstantiation) S.MarkVariableReferenced(VD->getLocation(), VD); @@ -5972,40 +6309,47 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { if (!MD) continue; - if (Member->getAttr<DLLExportAttr>()) { - if (MD->isUserProvided()) { - // Instantiate non-default class member functions ... + if (MD->isUserProvided()) { + // Instantiate non-default class member functions ... - // .. except for certain kinds of template specializations. - if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) - continue; + // .. except for certain kinds of template specializations. + if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) + continue; + + // If this is an MS ABI dllexport default constructor, instantiate any + // default arguments. + if (S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + auto *CD = dyn_cast<CXXConstructorDecl>(MD); + if (CD && CD->isDefaultConstructor() && TSK == TSK_Undeclared) { + S.InstantiateDefaultCtorDefaultArgs(CD); + } + } - S.MarkFunctionReferenced(Class->getLocation(), MD); + S.MarkFunctionReferenced(Class->getLocation(), MD); - // The function will be passed to the consumer when its definition is - // encountered. - } else if (MD->isExplicitlyDefaulted()) { - // Synthesize and instantiate explicitly defaulted methods. - S.MarkFunctionReferenced(Class->getLocation(), MD); + // The function will be passed to the consumer when its definition is + // encountered. + } else if (MD->isExplicitlyDefaulted()) { + // Synthesize and instantiate explicitly defaulted methods. + S.MarkFunctionReferenced(Class->getLocation(), MD); - if (TSK != TSK_ExplicitInstantiationDefinition) { - // Except for explicit instantiation defs, we will not see the - // definition again later, so pass it to the consumer now. - S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); - } - } else if (!MD->isTrivial() || - MD->isCopyAssignmentOperator() || - MD->isMoveAssignmentOperator()) { - // Synthesize and instantiate non-trivial implicit methods, and the copy - // and move assignment operators. The latter are exported even if they - // are trivial, because the address of an operator can be taken and - // should compare equal across libraries. - S.MarkFunctionReferenced(Class->getLocation(), MD); - - // There is no later point when we will see the definition of this - // function, so pass it to the consumer now. + if (TSK != TSK_ExplicitInstantiationDefinition) { + // Except for explicit instantiation defs, we will not see the + // definition again later, so pass it to the consumer now. S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); } + } else if (!MD->isTrivial() || + MD->isCopyAssignmentOperator() || + MD->isMoveAssignmentOperator()) { + // Synthesize and instantiate non-trivial implicit methods, and the copy + // and move assignment operators. The latter are exported even if they + // are trivial, because the address of an operator can be taken and + // should compare equal across libraries. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + // There is no later point when we will see the definition of this + // function, so pass it to the consumer now. + S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); } } } @@ -6194,6 +6538,17 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (!ClassAttr) return; + // MSVC allows imported or exported template classes that have UniqueExternal + // linkage. This occurs when the template class has been instantiated with + // a template parameter which itself has internal linkage. + // We drop the attribute to avoid exporting or importing any members. + if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isPS()) && + (!Class->isExternallyVisible() && Class->hasExternalFormalLinkage())) { + Class->dropAttrs<DLLExportAttr, DLLImportAttr>(); + return; + } + if (!Class->isExternallyVisible()) { Diag(Class->getLocation(), diag::err_attribute_dll_not_extern) << Class << ClassAttr; @@ -6507,7 +6862,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; bool DtorIsTrivialForCall = false; - // If a class has at least one non-deleted, trivial copy constructor, it + // If a class has at least one eligible, trivial copy constructor, it // is passed according to the C ABI. Otherwise, it is passed indirectly. // // Note: This permits classes with non-trivial copy or move ctors to be @@ -6522,7 +6877,8 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, } } else { for (const CXXConstructorDecl *CD : D->ctors()) { - if (CD->isCopyConstructor() && !CD->isDeleted()) { + if (CD->isCopyConstructor() && !CD->isDeleted() && + !CD->isIneligibleOrNotSelected()) { if (CD->isTrivial()) CopyCtorIsTrivial = true; if (CD->isTrivialForCall()) @@ -6588,7 +6944,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, return false; for (const CXXMethodDecl *MD : D->methods()) { - if (MD->isDeleted()) + if (MD->isDeleted() || MD->isIneligibleOrNotSelected()) continue; auto *CD = dyn_cast<CXXConstructorDecl>(MD); @@ -6656,7 +7012,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; } @@ -6842,7 +7198,8 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // Define defaulted constexpr virtual functions that override a base class // function right away. // FIXME: We can defer doing this until the vtable is marked as used. - if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods()) + if (CSM != CXXInvalid && !M->isDeleted() && M->isDefaulted() && + M->isConstexpr() && M->size_overridden_methods()) DefineDefaultedFunction(*this, M, M->getLocation()); if (!Incomplete) @@ -6925,11 +7282,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 @@ -7073,6 +7431,11 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, bool ConstRHS, CXXConstructorDecl *InheritedCtor = nullptr, Sema::InheritedConstructorInfo *Inherited = nullptr) { + // Suppress duplicate constraint checking here, in case a constraint check + // caused us to decide to do this. Any truely recursive checks will get + // caught during these checks anyway. + Sema::SatisfactionStackResetRAII SSRAII{S}; + // If we're inheriting a constructor, see if we need to call it for this base // class. if (InheritedCtor) { @@ -7169,8 +7532,8 @@ static bool defaultedSpecialMemberIsConstexpr( // class is a constexpr function, and for (const auto &B : ClassDecl->bases()) { const RecordType *BaseType = B.getType()->getAs<RecordType>(); - if (!BaseType) continue; - + if (!BaseType) + continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg, InheritedCtor, Inherited)) @@ -7297,13 +7660,15 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) { if (DefKind.isSpecialMember() ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD), - DefKind.asSpecialMember()) + DefKind.asSpecialMember(), + FD->getDefaultLoc()) : CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison())) FD->setInvalidDecl(); } bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, - CXXSpecialMember CSM) { + CXXSpecialMember CSM, + SourceLocation DefaultLoc) { CXXRecordDecl *RD = MD->getParent(); assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid && @@ -7334,7 +7699,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. @@ -7351,7 +7716,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, } } - const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *Type = MD->getType()->castAs<FunctionProtoType>(); bool CanHaveConstParam = false; if (CSM == CXXCopyConstructor) @@ -7363,9 +7728,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.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)) { @@ -7375,7 +7744,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 { @@ -7384,10 +7753,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. @@ -7439,15 +7829,33 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // FIXME: This should not apply if the member is deleted. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); + + // C++14 [dcl.constexpr]p6 (CWG DR647/CWG DR1358): + // If the instantiated template specialization of a constexpr function + // template or member function of a class template would fail to satisfy + // the requirements for a constexpr function or constexpr constructor, that + // specialization is still a constexpr function or constexpr constructor, + // even though a call to such a function cannot appear in a constant + // expression. + if (MD->isTemplateInstantiation() && MD->isConstexpr()) + Constexpr = true; + if ((getLangOpts().CPlusPlus20 || (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(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; } @@ -7470,10 +7878,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::makeArrayRef(&ArgType, - ExpectedParams), - EPI)); + MD->setType( + Context.getFunctionType(ReturnType, Type->getParamTypes(), EPI)); } } @@ -7484,8 +7890,11 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) << CSM; if (ShouldDeleteForTypeMismatch) { Diag(MD->getLocation(), diag::note_deleted_type_mismatch) << CSM; - } else { - ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true); + } else if (ShouldDeleteSpecialMember(MD, CSM, nullptr, + /*Diagnose*/ true) && + DefaultLoc.isValid()) { + Diag(DefaultLoc, diag::note_replace_equals_default_to_delete) + << FixItHint::CreateReplacement(DefaultLoc, "delete"); } } if (ShouldDeleteForTypeMismatch && !HadError) { @@ -7580,6 +7989,10 @@ protected: // followed by the non-static data members of C for (FieldDecl *Field : Record->fields()) { + // C++23 [class.bit]p2: + // Unnamed bit-fields are not members ... + if (Field->isUnnamedBitfield()) + continue; // Recursively expand anonymous structs. if (Field->isAnonymousStructOrUnion()) { if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(), @@ -7743,7 +8156,8 @@ private: OverloadCandidateSet CandidateSet( FD->getLocation(), OverloadCandidateSet::CSK_Operator, OverloadCandidateSet::OperatorRewriteInfo( - OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates)); + OO, FD->getLocation(), + /*AllowRewrittenCandidates=*/!SpaceshipCandidates)); /// C++2a [class.compare.default]p1 [P2002R0]: /// [...] the defaulted function itself is never a candidate for overload @@ -7771,9 +8185,21 @@ private: DCK == DefaultedComparisonKind::Relational) && !Best->RewriteKind) { if (Diagnose == ExplainDeleted) { - S.Diag(Best->Function->getLocation(), - diag::note_defaulted_comparison_not_rewritten_callee) - << FD; + if (Best->Function) { + S.Diag(Best->Function->getLocation(), + diag::note_defaulted_comparison_not_rewritten_callee) + << FD; + } else { + assert(Best->Conversions.size() == 2 && + Best->Conversions[0].isUserDefined() && + "non-user-defined conversion from class to built-in " + "comparison"); + S.Diag(Best->Conversions[0] + .UserDefined.FoundConversionFunction.getDecl() + ->getLocation(), + diag::note_defaulted_comparison_not_rewritten_conversion) + << FD; + } } return Result::deleted(); } @@ -7870,7 +8296,7 @@ private: "invalid builtin comparison"); if (NeedsDeducing) { - Optional<ComparisonCategoryType> Cat = + std::optional<ComparisonCategoryType> Cat = getComparisonCategoryForBuiltinCmp(T); assert(Cat && "no category for builtin comparison?"); R.Category = *Cat; @@ -7929,7 +8355,8 @@ private: if (Diagnose == ExplainDeleted) { S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function) - << FD << Subobj.Kind << Subobj.Decl; + << FD << (OO == OO_EqualEqual || OO == OO_ExclaimEqual) + << Subobj.Kind << Subobj.Decl; // For a three-way comparison, list both the candidates for the // original operator and the candidates for the synthesized operator. @@ -8103,7 +8530,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()) @@ -8157,7 +8585,7 @@ private: if (ReturnFalse.isInvalid()) return StmtError(); - return S.ActOnIfStmt(Loc, false, Loc, nullptr, + return S.ActOnIfStmt(Loc, IfStatementKind::Ordinary, Loc, nullptr, S.ActOnCondition(nullptr, Loc, NotCond.get(), Sema::ConditionKind::Boolean), Loc, ReturnFalse.get(), SourceLocation(), nullptr); @@ -8312,8 +8740,8 @@ private: return StmtError(); // if (...) - return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, Loc, InitStmt, Cond, Loc, - ReturnStmt.get(), + return S.ActOnIfStmt(Loc, IfStatementKind::Ordinary, Loc, InitStmt, Cond, + Loc, ReturnStmt.get(), /*ElseLoc=*/SourceLocation(), /*Else=*/nullptr); } @@ -8371,9 +8799,6 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, DefaultedComparisonKind DCK) { assert(DCK != DefaultedComparisonKind::None && "not a defaulted comparison"); - CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext()); - assert(RD && "defaulted comparison is not defaulted in a class"); - // Perform any unqualified lookups we're going to need to default this // function. if (S) { @@ -8387,56 +8812,48 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // C++2a [class.compare.default]p1: // A defaulted comparison operator function for some class C shall be a // non-template function declared in the member-specification of C that is - // -- a non-static const member of C having one parameter of type - // const C&, or + // -- a non-static const non-volatile member of C having one parameter of + // type const C& and either no ref-qualifier or the ref-qualifier &, or // -- a friend of C having two parameters of type const C& or two // parameters of type C. - QualType ExpectedParmType1 = Context.getRecordType(RD); - QualType ExpectedParmType2 = - Context.getLValueReferenceType(ExpectedParmType1.withConst()); - if (isa<CXXMethodDecl>(FD)) - ExpectedParmType1 = ExpectedParmType2; - for (const ParmVarDecl *Param : FD->parameters()) { - if (!Param->getType()->isDependentType() && - !Context.hasSameType(Param->getType(), ExpectedParmType1) && - !Context.hasSameType(Param->getType(), ExpectedParmType2)) { - // Don't diagnose an implicit 'operator=='; we will have diagnosed the - // corresponding defaulted 'operator<=>' already. - if (!FD->isImplicit()) { - Diag(FD->getLocation(), diag::err_defaulted_comparison_param) - << (int)DCK << Param->getType() << ExpectedParmType1 - << !isa<CXXMethodDecl>(FD) - << ExpectedParmType2 << Param->getSourceRange(); - } - return true; - } - } - if (FD->getNumParams() == 2 && - !Context.hasSameType(FD->getParamDecl(0)->getType(), - FD->getParamDecl(1)->getType())) { - if (!FD->isImplicit()) { - Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch) - << (int)DCK - << FD->getParamDecl(0)->getType() - << FD->getParamDecl(0)->getSourceRange() - << FD->getParamDecl(1)->getType() - << FD->getParamDecl(1)->getSourceRange(); - } - return true; - } - // ... non-static const member ... - if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext()); + bool IsMethod = isa<CXXMethodDecl>(FD); + if (IsMethod) { + auto *MD = cast<CXXMethodDecl>(FD); assert(!MD->isStatic() && "comparison function cannot be a static member"); - if (!MD->isConst()) { - SourceLocation InsertLoc; - if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc()) - InsertLoc = getLocForEndOfToken(Loc.getRParenLoc()); + + if (MD->getRefQualifier() == RQ_RValue) { + Diag(MD->getLocation(), diag::err_ref_qualifier_comparison_operator); + + // Remove the ref qualifier to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.RefQualifier = RQ_None; + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } + + // If we're out-of-class, this is the class we're comparing. + if (!RD) + RD = MD->getParent(); + 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) - << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const"); + Diag(Loc, diag::err_defaulted_comparison_non_const) + << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const"); } // Add the 'const' to the type to recover. @@ -8446,9 +8863,112 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, MD->setType(Context.getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI)); } - } else { - // A non-member function declared in a class must be a friend. + + if (MD->isVolatile()) { + Diag(MD->getLocation(), diag::err_volatile_comparison_operator); + + // Remove the 'volatile' from the type to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals.removeVolatile(); + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } + } + + 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) + << int(IsMethod) << int(DCK); + return true; + } + + const ParmVarDecl *KnownParm = nullptr; + for (const ParmVarDecl *Param : FD->parameters()) { + if (Param->isExplicitObjectParameter()) + continue; + QualType ParmTy = Param->getType(); + + if (!KnownParm) { + auto CTy = ParmTy; + // Is it `T const &`? + bool Ok = !IsMethod; + QualType ExpectedTy; + if (RD) + ExpectedTy = Context.getRecordType(RD); + if (auto *Ref = CTy->getAs<ReferenceType>()) { + CTy = Ref->getPointeeType(); + if (RD) + ExpectedTy.addConst(); + Ok = true; + } + + // Is T a class? + if (!Ok) { + } else if (RD) { + if (!RD->isDependentType() && !Context.hasSameType(CTy, ExpectedTy)) + Ok = false; + } else if (auto *CRD = CTy->getAsRecordDecl()) { + RD = cast<CXXRecordDecl>(CRD); + } else { + Ok = false; + } + + if (Ok) { + KnownParm = Param; + } else { + // Don't diagnose an implicit 'operator=='; we will have diagnosed the + // corresponding defaulted 'operator<=>' already. + if (!FD->isImplicit()) { + if (RD) { + QualType PlainTy = Context.getRecordType(RD); + QualType RefTy = + Context.getLValueReferenceType(PlainTy.withConst()); + Diag(FD->getLocation(), diag::err_defaulted_comparison_param) + << int(DCK) << ParmTy << RefTy << int(!IsMethod) << PlainTy + << Param->getSourceRange(); + } else { + assert(!IsMethod && "should know expected type for method"); + Diag(FD->getLocation(), + diag::err_defaulted_comparison_param_unknown) + << int(DCK) << ParmTy << Param->getSourceRange(); + } + } + return true; + } + } else if (!Context.hasSameType(KnownParm->getType(), ParmTy)) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch) + << int(DCK) << KnownParm->getType() << KnownParm->getSourceRange() + << ParmTy << Param->getSourceRange(); + return true; + } + } + + assert(RD && "must have determined class"); + if (IsMethod) { + } else if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { + // In-class, must be a friend decl. assert(FD->getFriendObjectKind() && "expected a friend declaration"); + } else { + // Out of class, require the defaulted comparison to be a friend (of a + // complete type). + if (RequireCompleteType(FD->getLocation(), Context.getRecordType(RD), + diag::err_defaulted_comparison_not_friend, int(DCK), + int(1))) + return true; + + if (llvm::none_of(RD->friends(), [&](const FriendDecl *F) { + return FD->getCanonicalDecl() == + F->getFriendDecl()->getCanonicalDecl(); + })) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_not_friend) + << int(DCK) << int(0) << RD; + Diag(RD->getCanonicalDecl()->getLocation(), diag::note_declared_at); + return true; + } } // C++2a [class.eq]p1, [class.rel]p1: @@ -8465,10 +8985,11 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // C++2a [class.spaceship]p2 [P2002R0]: // Let R be the declared return type [...]. If R is auto, [...]. Otherwise, // R shall not contain a placeholder type. - if (DCK == DefaultedComparisonKind::ThreeWay && - FD->getDeclaredReturnType()->getContainedDeducedType() && - !Context.hasSameType(FD->getDeclaredReturnType(), - Context.getAutoDeductType())) { + if (QualType RT = FD->getDeclaredReturnType(); + DCK == DefaultedComparisonKind::ThreeWay && + RT->getContainedDeducedType() && + (!Context.hasSameType(RT, Context.getAutoDeductType()) || + RT->getContainedAutoType()->isConstrained())) { Diag(FD->getLocation(), diag::err_defaulted_comparison_deduced_return_type_not_auto) << (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy @@ -8487,10 +9008,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, bool First = FD == FD->getCanonicalDecl(); - // If we want to delete the function, then do so; there's nothing else to - // check in that case. - if (Info.Deleted) { - if (!First) { + if (!First) { + if (Info.Deleted) { // C++11 [dcl.fct.def.default]p4: // [For a] user-provided explicitly-defaulted function [...] if such a // function is implicitly defined as deleted, the program is ill-formed. @@ -8504,7 +9023,21 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, .visit(); return true; } + if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { + // C++20 [class.compare.default]p1: + // [...] A definition of a comparison operator as defaulted that appears + // in a class shall be the first declaration of that function. + Diag(FD->getLocation(), diag::err_non_first_default_compare_in_class) + << (int)DCK; + Diag(FD->getCanonicalDecl()->getLocation(), + diag::note_previous_declaration); + return true; + } + } + // If we want to delete the function, then do so; there's nothing else to + // check in that case. + if (Info.Deleted) { SetDeclDeleted(FD, FD->getLocation()); if (!inTemplateInstantiation() && !FD->isImplicit()) { Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted) @@ -8512,6 +9045,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, DefaultedComparisonAnalyzer(*this, RD, FD, DCK, DefaultedComparisonAnalyzer::ExplainDeleted) .visit(); + if (FD->getDefaultLoc().isValid()) + Diag(FD->getDefaultLoc(), diag::note_replace_equals_default_to_delete) + << FixItHint::CreateReplacement(FD->getDefaultLoc(), "delete"); } return false; } @@ -8541,12 +9077,25 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // the requirements for a constexpr function [...] // The only relevant requirements are that the parameter and return types are // literal types. The remaining conditions are checked by the analyzer. + // + // We support P2448R2 in language modes earlier than C++23 as an extension. + // The concept of constexpr-compatible was removed. + // C++23 [dcl.fct.def.default]p3 [P2448R2] + // A function explicitly defaulted on its first declaration is implicitly + // inline, and is implicitly constexpr if it is constexpr-suitable. + // C++23 [dcl.constexpr]p3 + // A function is constexpr-suitable if + // - it is not a coroutine, and + // - if the function is a constructor or destructor, its class does not + // have any virtual base classes. if (FD->isConstexpr()) { if (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) && CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) && !Info.Constexpr) { Diag(FD->getBeginLoc(), - diag::err_incorrect_defaulted_comparison_constexpr) + getLangOpts().CPlusPlus23 + ? diag::warn_cxx23_compat_defaulted_comparison_constexpr_mismatch + : diag::ext_defaulted_comparison_constexpr_mismatch) << FD->isImplicit() << (int)DCK << FD->isConsteval(); DefaultedComparisonAnalyzer(*this, RD, FD, DCK, DefaultedComparisonAnalyzer::ExplainConstexpr) @@ -8606,7 +9155,10 @@ void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD, { // Build and set up the function body. - CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent()); + // The first parameter has type maybe-ref-to maybe-const T, use that to get + // the type of the class being compared. + auto PT = FD->getParamDecl(0)->getType(); + CXXRecordDecl *RD = PT.getNonReferenceType()->getAsCXXRecordDecl(); SourceLocation BodyLoc = FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation(); StmtResult Body = @@ -8721,9 +9273,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(); } } @@ -8891,7 +9443,18 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( // must be accessible and non-deleted, but need not be trivial. Such a // destructor is never actually called, but is semantically checked as // if it were. - DiagKind = 4; + if (CSM == Sema::CXXDefaultConstructor) { + // [class.default.ctor]p2: + // A defaulted default constructor for class X is defined as deleted if + // - X is a union that has a variant member with a non-trivial default + // constructor and no variant member of X has a default member + // initializer + const auto *RD = cast<CXXRecordDecl>(Field->getParent()); + if (!RD->hasInClassInitializer()) + DiagKind = 4; + } else { + DiagKind = 4; + } } if (DiagKind == -1) @@ -9032,13 +9595,12 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { << !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } - // C++11 [class.ctor]p5: any non-variant non-static data member of - // const-qualified type (or array thereof) with no - // brace-or-equal-initializer does not have a user-provided default - // constructor. + // C++11 [class.ctor]p5 (modified by DR2394): any non-variant non-static + // data member of const-qualified type (or array thereof) with no + // brace-or-equal-initializer is not const-default-constructible. if (!inUnion() && FieldType.isConstQualified() && !FD->hasInClassInitializer() && - (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) { + (!FieldRecord || !FieldRecord->allowConstDefaultInit())) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) << !!ICI << MD->getParent() << FD << FD->getType() << /*Const*/1; @@ -9108,7 +9670,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { } // Don't check the implicit member of the anonymous union type. - // This is technically non-conformant, but sanity demands it. + // This is technically non-conformant but supported, and we have a + // diagnostic for this elsewhere. return false; } @@ -9592,11 +10155,22 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, case CXXCopyConstructor: case CXXCopyAssignment: { - // Trivial copy operations always have const, non-volatile parameter types. - ConstArg = true; - const ParmVarDecl *Param0 = MD->getParamDecl(0); + const ParmVarDecl *Param0 = MD->getNonObjectParameter(0); const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>(); - if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) { + + // When ClangABICompat14 is true, CXX copy constructors will only be trivial + // if they are not user-provided and their parameter-type-list is equivalent + // to the parameter-type-list of an implicit declaration. This maintains the + // behavior before dr2171 was implemented. + // + // Otherwise, if ClangABICompat14 is false, All copy constructors can be + // trivial, if they are not user-provided, regardless of the qualifiers on + // the reference type. + const bool ClangABICompat14 = Context.getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver14; + if (!RT || + ((RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) && + ClangABICompat14)) { if (Diagnose) Diag(Param0->getLocation(), diag::note_nontrivial_param_type) << Param0->getSourceRange() << Param0->getType() @@ -9604,13 +10178,15 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, Context.getRecordType(RD).withConst()); return false; } + + ConstArg = RT->getPointeeType().isConstQualified(); break; } 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()) { @@ -9778,7 +10354,7 @@ public: }; } // end anonymous namespace -/// Add the most overriden methods from MD to Methods +/// Add the most overridden methods from MD to Methods static void AddMostOverridenMethods(const CXXMethodDecl *MD, llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) { if (MD->size_overridden_methods() == 0) @@ -9937,10 +10513,12 @@ void Sema::ActOnFinishCXXMemberSpecification( Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL; } - ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( - // strict aliasing violation! - reinterpret_cast<Decl**>(FieldCollector->getCurFields()), - FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); + ActOnFields(S, RLoc, TagDecl, + llvm::ArrayRef( + // strict aliasing violation! + reinterpret_cast<Decl **>(FieldCollector->getCurFields()), + FieldCollector->getCurNumFields()), + LBrac, RBrac, AttrList); CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl)); } @@ -10506,7 +11084,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, EPI.Variadic = false; EPI.TypeQuals = Qualifiers(); EPI.RefQualifier = RQ_None; - return Context.getFunctionType(Context.VoidTy, None, EPI); + return Context.getFunctionType(Context.VoidTy, std::nullopt, EPI); } static void extendLeft(SourceRange &R, SourceRange Before) { @@ -10574,15 +11152,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); @@ -10609,7 +11197,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, PastFunctionChunk = true; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::Array: NeedsTypedef = true; extendRight(After, Chunk.getSourceRange()); @@ -10682,7 +11270,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // of the errors above fired) and with the conversion type as the // return type. if (D.isInvalidType()) - R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); + R = Context.getFunctionType(ConvType, std::nullopt, + Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20) @@ -10732,13 +11321,110 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { << ClassType << ConvType; } - if (FunctionTemplateDecl *ConversionTemplate - = Conversion->getDescribedFunctionTemplate()) + if (FunctionTemplateDecl *ConversionTemplate = + Conversion->getDescribedFunctionTemplate()) { + if (const auto *ConvTypePtr = ConvType->getAs<PointerType>()) { + ConvType = ConvTypePtr->getPointeeType(); + } + if (ConvType->isUndeducedAutoType()) { + Diag(Conversion->getTypeSpecStartLoc(), diag::err_auto_not_allowed) + << getReturnTypeLoc(Conversion).getSourceRange() + << llvm::to_underlying(ConvType->getAs<AutoType>()->getKeyword()) + << /* in declaration of conversion function template= */ 24; + } + return ConversionTemplate; + } 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. @@ -10772,8 +11458,8 @@ struct BadSpecifierDiagnoser { /// Check the validity of a declarator that we parsed for a deduction-guide. /// These aren't actually declarators in the grammar, so we need to check that /// the user didn't specify any pieces that are not part of the deduction-guide -/// grammar. -void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, +/// grammar. Return true on invalid deduction-guide. +bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC) { TemplateName GuidedTemplate = D.getName().TemplateName.get().get(); TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl(); @@ -10786,7 +11472,7 @@ void 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(); @@ -10823,7 +11509,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, } if (D.isInvalidType()) - return; + return true; // Check the declarator is simple enough. bool FoundFunction = false; @@ -10836,14 +11522,13 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, << D.getSourceRange(); break; } - if (!Chunk.Fun.hasTrailingReturnType()) { - Diag(D.getName().getBeginLoc(), - diag::err_deduction_guide_no_trailing_return_type); - break; - } + if (!Chunk.Fun.hasTrailingReturnType()) + return Diag(D.getName().getBeginLoc(), + diag::err_deduction_guide_no_trailing_return_type); // Check that the return type is written as a specialization of // the template specified as the deduction-guide's name. + // The template name may not be qualified. [temp.deduct.guide] ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType(); TypeSourceInfo *TSI = nullptr; QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI); @@ -10851,11 +11536,17 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, bool AcceptableReturnType = false; bool MightInstantiateToSpecialization = false; if (auto RetTST = - TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) { + TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) { TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); bool TemplateMatches = Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); - if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches) + auto TKind = SpecifiedName.getKind(); + // A Using TemplateName can't actually be valid (either it's qualified, or + // we're in the wrong scope). But we have diagnosed these problems + // already. + bool SimplyWritten = TKind == TemplateName::Template || + TKind == TemplateName::UsingTemplate; + if (SimplyWritten && TemplateMatches) AcceptableReturnType = true; else { // This could still instantiate to the right type, unless we know it @@ -10868,13 +11559,12 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, MightInstantiateToSpecialization = true; } - if (!AcceptableReturnType) { - Diag(TSI->getTypeLoc().getBeginLoc(), - diag::err_deduction_guide_bad_trailing_return_type) - << GuidedTemplate << TSI->getType() - << MightInstantiateToSpecialization - << TSI->getTypeLoc().getSourceRange(); - } + if (!AcceptableReturnType) + return Diag(TSI->getTypeLoc().getBeginLoc(), + diag::err_deduction_guide_bad_trailing_return_type) + << GuidedTemplate << TSI->getType() + << MightInstantiateToSpecialization + << TSI->getTypeLoc().getSourceRange(); // Keep going to check that we don't have any inner declarator pieces (we // could still have a function returning a pointer to a function). @@ -10882,7 +11572,9 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, } if (D.isFunctionDefinition()) + // we can still create a valid deduction guide here. Diag(D.getIdentifierLoc(), diag::err_deduction_guide_defines_function); + return false; } //===----------------------------------------------------------------------===// @@ -10897,6 +11589,11 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, NamespaceDecl *PrevNS) { assert(*IsInline != PrevNS->isInline()); + // 'inline' must appear on the original definition, but not necessarily + // on all extension definitions, so the note should point to the first + // definition to avoid confusion. + PrevNS = PrevNS->getFirstDecl(); + if (PrevNS->isInline()) // The user probably just forgot the 'inline', so suggest that it // be added back. @@ -10911,10 +11608,13 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, /// ActOnStartNamespaceDef - This is called at the start of a namespace /// definition. -Decl *Sema::ActOnStartNamespaceDef( - Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc, - SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace, - const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UD) { +Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, + SourceLocation InlineLoc, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation LBrace, + const ParsedAttributesView &AttrList, + UsingDirectiveDecl *&UD, bool IsNested) { SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; // For anonymous namespace, take the location of the left brace. SourceLocation Loc = II ? IdentLoc : LBrace; @@ -10926,6 +11626,20 @@ Decl *Sema::ActOnStartNamespaceDef( NamespaceDecl *PrevNS = nullptr; if (II) { + // C++ [namespace.std]p7: + // A translation unit shall not declare namespace std to be an inline + // namespace (9.8.2). + // + // Precondition: the std namespace is in the file scope and is declared to + // be inline + auto DiagnoseInlineStdNS = [&]() { + assert(IsInline && II->isStr("std") && + CurContext->getRedeclContext()->isTranslationUnit() && + "Precondition of DiagnoseInlineStdNS not met"); + Diag(InlineLoc, diag::err_inline_namespace_std) + << SourceRange(InlineLoc, InlineLoc.getLocWithOffset(6)); + IsInline = false; + }; // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not // have been previously defined in the declarative region in @@ -10946,7 +11660,10 @@ Decl *Sema::ActOnStartNamespaceDef( if (PrevNS) { // This is an extended namespace definition. - if (IsInline != PrevNS->isInline()) + if (IsInline && II->isStr("std") && + CurContext->getRedeclContext()->isTranslationUnit()) + DiagnoseInlineStdNS(); + else if (IsInline != PrevNS->isInline()) DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II, &IsInline, PrevNS); } else if (PrevDecl) { @@ -10958,6 +11675,8 @@ Decl *Sema::ActOnStartNamespaceDef( // Continue on to push Namespc as current DeclContext and return it. } else if (II->isStr("std") && CurContext->getRedeclContext()->isTranslationUnit()) { + if (IsInline) + DiagnoseInlineStdNS(); // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. PrevNS = getStdNamespace(); @@ -10984,8 +11703,8 @@ Decl *Sema::ActOnStartNamespaceDef( &IsInline, PrevNS); } - NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline, - StartLoc, Loc, II, PrevNS); + NamespaceDecl *Namespc = NamespaceDecl::Create( + Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS, IsNested); if (IsInvalid) Namespc->setInvalidDecl(); @@ -11089,21 +11808,6 @@ NamespaceDecl *Sema::getStdNamespace() const { return cast_or_null<NamespaceDecl>( StdNamespace.get(Context.getExternalSource())); } - -NamespaceDecl *Sema::lookupStdExperimentalNamespace() { - if (!StdExperimentalNamespaceCache) { - if (auto Std = getStdNamespace()) { - LookupResult Result(*this, &PP.getIdentifierTable().get("experimental"), - SourceLocation(), LookupNamespaceName); - if (!LookupQualifiedName(Result, Std) || - !(StdExperimentalNamespaceCache = - Result.getAsSingle<NamespaceDecl>())) - Result.suppressDiagnostics(); - } - } - return StdExperimentalNamespaceCache; -} - namespace { enum UnsupportedSTLSelect { @@ -11148,7 +11852,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 @@ -11246,13 +11951,16 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, NamespaceDecl *Sema::getOrCreateStdNamespace() { if (!StdNamespace) { // The "std" namespace has not yet been defined, so build one implicitly. - StdNamespace = NamespaceDecl::Create(Context, - Context.getTranslationUnitDecl(), - /*Inline=*/false, - SourceLocation(), SourceLocation(), - &PP.getIdentifierTable().get("std"), - /*PrevDecl=*/nullptr); + StdNamespace = NamespaceDecl::Create( + Context, Context.getTranslationUnitDecl(), + /*Inline=*/false, SourceLocation(), SourceLocation(), + &PP.getIdentifierTable().get("std"), + /*PrevDecl=*/nullptr, /*Nested=*/false); getStdNamespace()->setImplicit(true); + // We want the created NamespaceDecl to be available for redeclaration + // lookups, but not for regular name lookups. + Context.getTranslationUnitDecl()->addDecl(getStdNamespace()); + getStdNamespace()->clearIdentifierNamespace(); } return getStdNamespace(); @@ -11284,7 +11992,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { Ty->getAs<TemplateSpecializationType>()) { Template = dyn_cast_or_null<ClassTemplateDecl>( TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->getArgs(); + Arguments = TST->template_arguments().begin(); } if (!Template) return false; @@ -11363,7 +12071,9 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) { Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element), Context.getTrivialTypeSourceInfo(Element, Loc))); - return Context.getCanonicalType( + return Context.getElaboratedType( + ElaboratedTypeKeyword::None, + NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()), CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); } @@ -11414,6 +12124,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, @@ -11423,7 +12151,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); @@ -11625,30 +12362,40 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, - const DeclSpec &DS) { - switch (DS.getTypeSpecType()) { - case DeclSpec::TST_error: - // This will already have been diagnosed + SourceLocation IdentLoc, + IdentifierInfo &II, CXXScopeSpec *SS) { + assert(!SS->isInvalid() && "ScopeSpec is invalid"); + TypeSourceInfo *TSI = nullptr; + QualType EnumTy = GetTypeFromParser( + getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false, + /*HasTrailingDot=*/false, + /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false, + /*WantNontrivialTypeSourceInfo=*/true), + &TSI); + if (EnumTy.isNull()) { + Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS) + ? diag::err_using_enum_is_dependent + : diag::err_unknown_typename) + << II.getName() + << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc); return nullptr; + } - case DeclSpec::TST_enum: - break; - - case DeclSpec::TST_typename: - Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent); + auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl()); + if (!Enum) { + Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy; return nullptr; - - default: - llvm_unreachable("unexpected DeclSpec type"); } - // As with enum-decls, we ignore attributes for now. - auto *Enum = cast<EnumDecl>(DS.getRepAsDecl()); if (auto *Def = Enum->getDefinition()) Enum = Def; - auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, - DS.getTypeSpecTypeNameLoc(), Enum); + if (TSI == nullptr) + TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc); + + auto *UD = + BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, TSI, Enum); + if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); @@ -12192,7 +12939,7 @@ NamedDecl *Sema::BuildUsingDeclaration( // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration // even if hidden by ordinary names, *except* in a dependent context - // where it's important for the sanity of two-phase lookup. + // where they may be used by two-phase lookup. if (!IsInstantiation) R.setHideTags(false); @@ -12340,6 +13087,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, SourceLocation NameLoc, + TypeSourceInfo *EnumType, EnumDecl *ED) { bool Invalid = false; @@ -12366,7 +13114,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, Invalid = true; UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc, - EnumLoc, NameLoc, ED); + EnumLoc, NameLoc, EnumType); UD->setAccess(AS); CurContext->addDecl(UD); @@ -12708,7 +13456,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, // Salient point: SS doesn't have to name a base class as long as // lookup only finds members from base classes. Therefore we can - // diagnose here only if we can prove that that can't happen, + // diagnose here only if we can prove that can't happen, // i.e. if the class hierarchies provably don't intersect. // TODO: it would be nice if "definitely valid" results were cached @@ -12788,7 +13536,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, Previous.clear(); } - assert(Name.Kind == UnqualifiedIdKind::IK_Identifier && + assert(Name.getKind() == UnqualifiedIdKind::IK_Identifier && "name in alias declaration must be an identifier"); TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc, Name.StartLocation, @@ -12884,7 +13632,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, NewDecl->setInvalidDecl(); else if (OldDecl) { NewDecl->setPreviousDecl(OldDecl); - CheckRedeclarationModuleOwnership(NewDecl, OldDecl); + CheckRedeclarationInModule(NewDecl, OldDecl); } NewND = NewDecl; @@ -13178,7 +13926,8 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) { R.resolveKind(); R.suppressDiagnostics(); - CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/false); + CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/ false, + FD->isThisDeclarationADefinition()); } void Sema::setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem, @@ -13235,20 +13984,20 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), + getCurFPFeatures().isFPConstrained(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); - if (getLangOpts().CUDA) { + setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt); + + if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor, DefaultCon, /* ConstRHS */ false, /* Diagnose */ false); - } - - setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, None); // We don't need to use SpecialMemberIsTrivial here; triviality for default // constructors is easy to compute. @@ -13356,7 +14105,8 @@ Sema::findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, - BaseCtor->getExplicitSpecifier(), /*isInline=*/true, + BaseCtor->getExplicitSpecifier(), getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? BaseCtor->getConstexprKind() : ConstexprSpecKind::Unspecified, InheritedConstructor(Shadow, BaseCtor), @@ -13511,23 +14261,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); - CXXDestructorDecl *Destructor = - CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - QualType(), nullptr, /*isInline=*/true, - /*isImplicitlyDeclared=*/true, - Constexpr ? ConstexprSpecKind::Constexpr - : ConstexprSpecKind::Unspecified); + CXXDestructorDecl *Destructor = CXXDestructorDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, QualType(), nullptr, + getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, + /*isImplicitlyDeclared=*/true, + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); Destructor->setAccess(AS_public); Destructor->setDefaulted(); - if (getLangOpts().CUDA) { + setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt); + + if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor, Destructor, /* ConstRHS */ false, /* Diagnose */ false); - } - - setupImplicitSpecialMemberType(Destructor, Context.VoidTy, None); // We don't need to use SpecialMemberIsTrivial here; triviality for // destructors is easy to compute. @@ -13682,7 +14432,8 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) { FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); EPI.ExceptionSpec.Type = EST_Unevaluated; EPI.ExceptionSpec.SourceDecl = Destructor; - Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); + Destructor->setType( + Context.getFunctionType(Context.VoidTy, std::nullopt, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this @@ -14130,6 +14881,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { return nullptr; QualType ArgType = Context.getTypeDeclType(ClassDecl); + ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr, + ArgType, nullptr); LangAS AS = getDefaultCXXMethodAddrSpace(); if (AS != LangAS::Default) ArgType = Context.getAddrSpaceQualType(ArgType, AS); @@ -14152,6 +14905,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, + getCurFPFeatures().isFPConstrained(), /*isInline=*/true, Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); @@ -14159,14 +14913,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); - if (getLangOpts().CUDA) { + setupImplicitSpecialMemberType(CopyAssignment, RetType, ArgType); + + if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyAssignment, CopyAssignment, /* ConstRHS */ Const, /* Diagnose */ false); - } - - setupImplicitSpecialMemberType(CopyAssignment, RetType, ArgType); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, @@ -14208,13 +14961,10 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { CXXRecordDecl *RD = CopyOp->getParent(); CXXMethodDecl *UserDeclaredOperation = nullptr; - // In Microsoft mode, assignment operations don't affect constructors and - // vice versa. if (RD->hasUserDeclaredDestructor()) { UserDeclaredOperation = RD->getDestructor(); } else if (!isa<CXXConstructorDecl>(CopyOp) && - RD->hasUserDeclaredCopyConstructor() && - !S.getLangOpts().MSVCCompat) { + RD->hasUserDeclaredCopyConstructor()) { // Find any user-declared copy constructor. for (auto *I : RD->ctors()) { if (I->isCopyConstructor()) { @@ -14224,8 +14974,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { } assert(UserDeclaredOperation); } else if (isa<CXXConstructorDecl>(CopyOp) && - RD->hasUserDeclaredCopyAssignment() && - !S.getLangOpts().MSVCCompat) { + RD->hasUserDeclaredCopyAssignment()) { // Find any user-declared move assignment operator. for (auto *I : RD->methods()) { if (I->isCopyAssignmentOperator()) { @@ -14299,12 +15048,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(); } @@ -14316,8 +15064,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; @@ -14339,11 +15105,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, @@ -14409,9 +15175,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, MemberLookup.resolveKind(); MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup); - - MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/true, MemberLookup); - + MemberBuilder To(ObjectParameter, ObjectType, IsArrow, MemberLookup); // Build the copy of this field. StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType, To, From, @@ -14428,9 +15192,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, if (!Invalid) { // Add a "return *this;" - ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); - - StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); + 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; else @@ -14468,6 +15235,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // constructor rules. QualType ArgType = Context.getTypeDeclType(ClassDecl); + ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr, + ArgType, nullptr); LangAS AS = getDefaultCXXMethodAddrSpace(); if (AS != LangAS::Default) ArgType = Context.getAddrSpaceQualType(ArgType, AS); @@ -14486,6 +15255,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, + getCurFPFeatures().isFPConstrained(), /*isInline=*/true, Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); @@ -14493,14 +15263,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setDefaulted(); MoveAssignment->setImplicit(); - if (getLangOpts().CUDA) { + setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType); + + if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveAssignment, MoveAssignment, /* ConstRHS */ false, /* Diagnose */ false); - } - - setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, @@ -14610,8 +15379,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class, continue; // We're going to move the base classes of Base. Add them to the list. - for (auto &BI : Base->bases()) - Worklist.push_back(&BI); + llvm::append_range(Worklist, llvm::make_pointer_range(Base->bases())); } } } @@ -14660,7 +15428,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(); @@ -14674,8 +15442,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; @@ -14703,14 +15486,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, @@ -14775,8 +15557,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 " @@ -14798,10 +15580,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 @@ -14841,6 +15625,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; + ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr, + ArgType, nullptr); bool Const = ClassDecl->implicitCopyConstructorHasConstParam(); if (Const) ArgType = ArgType.withConst(); @@ -14865,7 +15651,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // member of its class. CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, - ExplicitSpecifier(), + ExplicitSpecifier(), getCurFPFeatures().isFPConstrained(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? ConstexprSpecKind::Constexpr @@ -14873,14 +15659,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); - if (getLangOpts().CUDA) { + setupImplicitSpecialMemberType(CopyConstructor, Context.VoidTy, ArgType); + + if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyConstructor, CopyConstructor, /* ConstRHS */ Const, /* Diagnose */ false); - } - - setupImplicitSpecialMemberType(CopyConstructor, Context.VoidTy, ArgType); // During template instantiation of special member functions we need a // reliable TypeSourceInfo for the parameter types in order to allow functions @@ -14965,7 +15750,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, : CopyConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( - ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); + ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false) + .getAs<Stmt>()); CopyConstructor->markUsed(Context); } @@ -14985,6 +15771,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; + ArgType = Context.getElaboratedType(ElaboratedTypeKeyword::None, nullptr, + ArgType, nullptr); LangAS AS = getDefaultCXXMethodAddrSpace(); if (AS != LangAS::Default) ArgType = Context.getAddrSpaceQualType(ClassType, AS); @@ -15005,7 +15793,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( // member of its class. CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, - ExplicitSpecifier(), + ExplicitSpecifier(), getCurFPFeatures().isFPConstrained(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? ConstexprSpecKind::Constexpr @@ -15013,14 +15801,13 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); - if (getLangOpts().CUDA) { + setupImplicitSpecialMemberType(MoveConstructor, Context.VoidTy, ArgType); + + if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveConstructor, MoveConstructor, /* ConstRHS */ false, /* Diagnose */ false); - } - - setupImplicitSpecialMemberType(MoveConstructor, Context.VoidTy, ArgType); // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, @@ -15091,8 +15878,9 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, ? MoveConstructor->getEndLoc() : MoveConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); - MoveConstructor->setBody(ActOnCompoundStmt( - Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); + MoveConstructor->setBody( + ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false) + .getAs<Stmt>()); MoveConstructor->markUsed(Context); } @@ -15117,7 +15905,10 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( CXXRecordDecl *Lambda = Conv->getParent(); FunctionDecl *CallOp = Lambda->getLambdaCallOperator(); - FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC); + FunctionDecl *Invoker = + CallOp->hasCXXExplicitFunctionObjectParameter() || CallOp->isStatic() + ? CallOp + : Lambda->getLambdaStaticInvoker(CC); if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) { CallOp = InstantiateFunctionDeclaration( @@ -15125,10 +15916,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( if (!CallOp) return; - Invoker = InstantiateFunctionDeclaration( - Invoker->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation); - if (!Invoker) - return; + if (CallOp != Invoker) { + Invoker = InstantiateFunctionDeclaration( + Invoker->getDescribedFunctionTemplate(), TemplateArgs, + CurrentLocation); + if (!Invoker) + return; + } } if (CallOp->isInvalidDecl()) @@ -15141,36 +15935,35 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( // to the PendingInstantiations. MarkFunctionReferenced(CurrentLocation, CallOp); - // Fill in the __invoke function with a dummy implementation. IR generation - // will fill in the actual details. Update its type in case it contained - // an 'auto'. - Invoker->markUsed(Context); - Invoker->setReferenced(); - Invoker->setType(Conv->getReturnType()->getPointeeType()); - Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); + if (Invoker != CallOp) { + // Fill in the __invoke function with a dummy implementation. IR generation + // will fill in the actual details. Update its type in case it contained + // an 'auto'. + Invoker->markUsed(Context); + Invoker->setReferenced(); + Invoker->setType(Conv->getReturnType()->getPointeeType()); + Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); + } // Construct the body of the conversion function { return __invoke; }. - Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), - VK_LValue, Conv->getLocation()); + Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), VK_LValue, + Conv->getLocation()); assert(FunctionRef && "Can't refer to __invoke function?"); Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); - Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(), - Conv->getLocation())); + Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(), + Conv->getLocation(), Conv->getLocation())); Conv->markUsed(Context); Conv->setReferenced(); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); - L->CompletedImplicitDefinition(Invoker); + if (Invoker != CallOp) + L->CompletedImplicitDefinition(Invoker); } } - - void Sema::DefineImplicitLambdaToBlockPointerConversion( - SourceLocation CurrentLocation, - CXXConversionDecl *Conv) -{ + SourceLocation CurrentLocation, CXXConversionDecl *Conv) { assert(!Conv->getParent()->isGenericLambda()); SynthesizedFunctionScope Scope(*this, Conv); @@ -15209,8 +16002,8 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( // Set the body of the conversion function. Stmt *ReturnS = Return.get(); - Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(), - Conv->getLocation())); + Conv->setBody(CompoundStmt::Create(Context, ReturnS, FPOptionsOverride(), + Conv->getLocation(), Conv->getLocation())); Conv->markUsed(Context); // We're done; notify the mutation listener, if any. @@ -15230,7 +16023,7 @@ static bool hasOneRealArgument(MultiExprArg Args) { if (!Args[1]->isDefaultArgument()) return false; - LLVM_FALLTHROUGH; + [[fallthrough]]; case 1: return !Args[0]->isDefaultArgument(); } @@ -15238,17 +16031,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: @@ -15261,7 +16049,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. @@ -15285,21 +16073,18 @@ 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); - if (DiagnoseUseOfDecl(Constructor, ConstructLoc)) + // The only way to get here is if we did overlaod resolution to find the + // shadow decl, so we don't need to worry about re-checking the trailing + // requires clause. + if (DiagnoseUseOfOverloadedDecl(Constructor, ConstructLoc)) return ExprError(); } @@ -15311,17 +16096,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()) && @@ -15329,88 +16109,20 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MarkFunctionReferenced(ConstructLoc, Constructor); if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) return ExprError(); - if (getLangOpts().SYCLIsDevice && - !checkSYCLDeviceFunction(ConstructLoc, Constructor)) - return ExprError(); return CheckForImmediateInvocation( CXXConstructExpr::Create( Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs, HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization, RequiresZeroInit, - static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), - ParenRange), + static_cast<CXXConstructionKind>(ConstructKind), ParenRange), Constructor); } -ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { - assert(Field->hasInClassInitializer()); - - // If we already have the in-class initializer nothing needs to be done. - if (Field->getInClassInitializer()) - return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext); - - // If we might have already tried and failed to instantiate, don't try again. - if (Field->isInvalidDecl()) - return ExprError(); - - // Maybe we haven't instantiated the in-class initializer. Go check the - // pattern FieldDecl to see if it has one. - CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent()); - - if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { - CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); - DeclContext::lookup_result Lookup = - ClassPattern->lookup(Field->getDeclName()); - - FieldDecl *Pattern = nullptr; - for (auto L : Lookup) { - if (isa<FieldDecl>(L)) { - Pattern = cast<FieldDecl>(L); - break; - } - } - assert(Pattern && "We must have set the Pattern!"); - - if (!Pattern->hasInClassInitializer() || - InstantiateInClassInitializer(Loc, Field, Pattern, - getTemplateInstantiationArgs(Field))) { - // Don't diagnose this again. - Field->setInvalidDecl(); - return ExprError(); - } - return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext); - } - - // DR1351: - // If the brace-or-equal-initializer of a non-static data member - // invokes a defaulted default constructor of its class or of an - // enclosing class in a potentially evaluated subexpression, the - // program is ill-formed. - // - // This resolution is unworkable: the exception specification of the - // default constructor can be needed in an unevaluated context, in - // particular, in the operand of a noexcept-expression, and we can be - // unable to compute an exception specification for an enclosed class. - // - // Any attempt to resolve the exception specification of a defaulted default - // constructor before the initializer is lexically complete will ultimately - // come here at which point we can diagnose it. - RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); - Diag(Loc, diag::err_default_member_initializer_not_yet_parsed) - << OutermostClass << Field; - Diag(Field->getEndLoc(), - diag::note_default_member_initializer_not_yet_parsed); - // Recover by marking the field invalid, unless we're in a SFINAE context. - if (!isSFINAEContext()) - Field->setInvalidDecl(); - return ExprError(); -} - void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; // If initializing the variable failed, don't also diagnose problems with - // the desctructor, they're likely related. + // the destructor, they're likely related. if (VD->getInit() && VD->getInit()->containsErrors()) return; @@ -15423,7 +16135,11 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { return; CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - + // The result of `LookupDestructor` might be nullptr if the destructor is + // invalid, in which case it is marked as `IneligibleOrNotSelected` and + // will not be selected by `CXXRecordDecl::getDestructor()`. + if (!Destructor) + return; // If this is an array, we'll require the destructor during initialization, so // we can skip over this. We still want to emit exit-time destructor warnings // though. @@ -15453,7 +16169,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { } } - if (!VD->hasGlobalStorage()) return; + if (!VD->hasGlobalStorage() || !VD->needsDestruction(Context)) + return; // Emit warning for non-trivial dtor in global scope (a real global, // class-static, function-static). @@ -15491,19 +16208,16 @@ bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; SmallVector<Expr *, 8> AllArgs; - bool Invalid = GatherArgumentsForCall(Loc, Constructor, - Proto, 0, - llvm::makeArrayRef(Args, NumArgs), - AllArgs, - CallType, AllowExplicit, - IsListInitialization); + bool Invalid = GatherArgumentsForCall( + Loc, Constructor, Proto, 0, llvm::ArrayRef(Args, NumArgs), AllArgs, + CallType, AllowExplicit, IsListInitialization); ConvertedArgs.append(AllArgs.begin(), AllArgs.end()); DiagnoseSentinelCalls(Constructor, Loc, AllArgs); CheckConstructorCall(Constructor, DeclInitType, - llvm::makeArrayRef(AllArgs.data(), AllArgs.size()), - Proto, Loc); + llvm::ArrayRef(AllArgs.data(), AllArgs.size()), Proto, + Loc); return Invalid; } @@ -15702,18 +16416,28 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if (Op == OO_New || Op == OO_Array_New) return CheckOperatorNewDeclaration(*this, FnDecl); - // C++ [over.oper]p6: - // An operator function shall either be a non-static member - // function or be a non-member function and have at least one - // parameter whose type is a class, a reference to a class, an - // enumeration, or a reference to an enumeration. + // C++ [over.oper]p7: + // An operator function shall either be a member function or + // be a non-member function and have at least one parameter + // whose type is a class, a reference to a class, an enumeration, + // or a reference to an enumeration. + // Note: Before C++23, a member function could not be static. The only member + // function allowed to be static is the call operator function. if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (MethodDecl->isStatic()) - return Diag(FnDecl->getLocation(), - diag::err_operator_overload_static) << FnDecl->getDeclName(); + if (MethodDecl->isStatic()) { + if (Op == OO_Call || Op == OO_Subscript) + Diag(FnDecl->getLocation(), + (LangOpts.CPlusPlus23 + ? diag::warn_cxx20_compat_operator_overload_static + : diag::ext_operator_overload_static)) + << FnDecl; + else + return Diag(FnDecl->getLocation(), diag::err_operator_overload_static) + << FnDecl; + } } else { bool ClassOrEnumParam = false; - for (auto Param : FnDecl->parameters()) { + for (auto *Param : FnDecl->parameters()) { QualType ParamType = Param->getType().getNonReferenceType(); if (ParamType->isDependentType() || ParamType->isRecordType() || ParamType->isEnumeralType()) { @@ -15732,14 +16456,29 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // An operator function cannot have default arguments (8.3.6), // except where explicitly stated below. // - // Only the function-call operator allows default arguments - // (C++ [over.call]p1). + // Only the function-call operator (C++ [over.call]p1) and the subscript + // operator (CWG2507) allow default arguments. if (Op != OO_Call) { - for (auto Param : FnDecl->parameters()) { - if (Param->hasDefaultArg()) - return Diag(Param->getLocation(), + ParmVarDecl *FirstDefaultedParam = nullptr; + for (auto *Param : FnDecl->parameters()) { + if (Param->hasDefaultArg()) { + FirstDefaultedParam = Param; + break; + } + } + if (FirstDefaultedParam) { + if (Op == OO_Subscript) { + Diag(FnDecl->getLocation(), LangOpts.CPlusPlus23 + ? diag::ext_subscript_overload + : diag::error_subscript_overload) + << FnDecl->getDeclName() << 1 + << FirstDefaultedParam->getDefaultArgRange(); + } else { + return Diag(FirstDefaultedParam->getLocation(), diag::err_operator_overload_default_arg) - << FnDecl->getDeclName() << Param->getDefaultArgRange(); + << FnDecl->getDeclName() + << FirstDefaultedParam->getDefaultArgRange(); + } } } @@ -15758,12 +16497,15 @@ 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); - if (Op != OO_Call && + 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) || (NumParams > 2))) { + (NumParams == 2 && !CanBeBinaryOperator) || (NumParams < 1) || + (NumParams > 2))) { // We have the wrong number of parameters. unsigned ErrorKind; if (CanBeUnaryOperator && CanBeBinaryOperator) { @@ -15775,19 +16517,26 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { "All non-call overloaded operators are unary or binary!"); ErrorKind = 1; // 1 -> binary } - return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be) << FnDecl->getDeclName() << NumParams << ErrorKind; } - // Overloaded operators other than operator() cannot be variadic. + if (Op == OO_Subscript && NumParams != 2) { + Diag(FnDecl->getLocation(), LangOpts.CPlusPlus23 + ? diag::ext_subscript_overload + : diag::error_subscript_overload) + << FnDecl->getDeclName() << (NumParams == 1 ? 0 : 2); + } + + // Overloaded operators other than operator() and operator[] cannot be + // variadic. if (Op != OO_Call && FnDecl->getType()->castAs<FunctionProtoType>()->isVariadic()) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic) - << FnDecl->getDeclName(); + << FnDecl->getDeclName(); } - // Some operators must be non-static member functions. + // Some operators must be member functions. if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be_member) @@ -15840,7 +16589,7 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef, // // As a DR resolution, we also allow placeholders for deduced class // template specializations. - if (SemaRef.getLangOpts().CPlusPlus20 && + if (SemaRef.getLangOpts().CPlusPlus20 && PmDecl && !PmDecl->isTemplateParameterPack() && (PmDecl->getType()->isRecordType() || PmDecl->getType()->getAs<DeducedTemplateSpecializationType>())) @@ -16020,7 +16769,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { // A parameter-declaration-clause containing a default argument is not // equivalent to any of the permitted forms. - for (auto Param : FnDecl->parameters()) { + for (auto *Param : FnDecl->parameters()) { if (Param->hasDefaultArg()) { Diag(Param->getDefaultArgRange().getBegin(), diag::err_literal_operator_default_argument) @@ -16029,15 +16778,18 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { } } - StringRef LiteralName - = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName(); - if (LiteralName[0] != '_' && + const IdentifierInfo *II = FnDecl->getDeclName().getCXXLiteralIdentifier(); + ReservedLiteralSuffixIdStatus Status = II->isReservedLiteralSuffixId(); + if (Status != ReservedLiteralSuffixIdStatus::NotReserved && !getSourceManager().isInSystemHeader(FnDecl->getLocation())) { - // C++11 [usrlit.suffix]p1: - // Literal suffix identifiers that do not start with an underscore - // are reserved for future standardization. + // C++23 [usrlit.suffix]p1: + // Literal suffix identifiers that do not start with an underscore are + // reserved for future standardization. Literal suffix identifiers that + // contain a double underscore __ are reserved for use by C++ + // implementations. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << static_cast<int>(Status) + << StringLiteralParser::isValidUDSuffix(getLangOpts(), II->getName()); } return false; @@ -16053,18 +16805,14 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Expr *LangStr, SourceLocation LBraceLoc) { StringLiteral *Lit = cast<StringLiteral>(LangStr); - if (!Lit->isAscii()) { - Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii) - << LangStr->getSourceRange(); - return nullptr; - } + 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(); @@ -16076,6 +16824,21 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, ExternLoc, LangStr->getExprLoc(), Language, LBraceLoc.isValid()); + + /// C++ [module.unit]p7.2.3 + /// - Otherwise, if the declaration + /// - ... + /// - ... + /// - appears within a linkage-specification, + /// it is attached to the global module. + /// + /// 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); + D->setLocalOwningModule(GlobalModule); + } + CurContext->addDecl(D); PushDeclContext(S, D); return D; @@ -16092,6 +16855,15 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec); LSDecl->setRBraceLoc(RBraceLoc); } + + // If the current module doesn't has Parent, it implies that the + // LinkageSpec isn't in the module created by itself. So we don't + // need to pop it. + if (getLangOpts().CPlusPlusModules && getCurrentModule() && + getCurrentModule()->isImplicitGlobalModule() && + getCurrentModule()->Parent) + PopImplicitGlobalModuleFragment(); + PopDeclContext(); return LinkageSpec; } @@ -16156,6 +16928,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; + if (!Invalid && BaseType.isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reftype_tc) << 1; + Invalid = true; + } + if (!Invalid && Mode != 1 && BaseType->isSizelessType()) { Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType; Invalid = true; @@ -16244,7 +17021,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch /// handler. Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D); bool Invalid = D.isInvalidType(); // Check for unexpanded parameter packs. @@ -16298,23 +17075,358 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc) { - StringLiteral *AssertMessage = - AssertMessageExpr ? cast<StringLiteral>(AssertMessageExpr) : nullptr; - if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) return nullptr; return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr, - AssertMessage, RParenLoc, false); + 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, + ASTContext &Context) { + if (!V.hasValue()) + return false; + + switch (V.getKind()) { + case APValue::ValueKind::Int: + if (T->isBooleanType()) { + // Bools are reduced to ints during evaluation, but for + // diagnostic purposes we want to print them as + // true or false. + int64_t BoolValue = V.getInt().getExtValue(); + assert((BoolValue == 0 || BoolValue == 1) && + "Bool type, but value is not 0 or 1"); + llvm::raw_svector_ostream OS(Str); + OS << (BoolValue ? "true" : "false"); + } else { + llvm::raw_svector_ostream OS(Str); + // Same is true for chars. + // 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; + + case APValue::ValueKind::Float: + V.getFloat().toString(Str); + break; + + case APValue::ValueKind::LValue: + if (V.isNullPointer()) { + llvm::raw_svector_ostream OS(Str); + OS << "nullptr"; + } else + return false; + break; + + case APValue::ValueKind::ComplexFloat: { + llvm::raw_svector_ostream OS(Str); + OS << '('; + V.getComplexFloatReal().toString(Str); + OS << " + "; + V.getComplexFloatImag().toString(Str); + OS << "i)"; + } break; + + case APValue::ValueKind::ComplexInt: { + llvm::raw_svector_ostream OS(Str); + OS << '('; + V.getComplexIntReal().toString(Str); + OS << " + "; + V.getComplexIntImag().toString(Str); + OS << "i)"; + } break; + + default: + return false; + } + + return true; +} + +/// Some Expression types are not useful to print notes about, +/// e.g. literals and values that have already been expanded +/// before such as int-valued template parameters. +static bool UsefulToPrintExpr(const Expr *E) { + E = E->IgnoreParenImpCasts(); + // Literals are pretty easy for humans to understand. + if (isa<IntegerLiteral, FloatingLiteral, CharacterLiteral, CXXBoolLiteralExpr, + CXXNullPtrLiteralExpr, FixedPointLiteral, ImaginaryLiteral>(E)) + return false; + + // These have been substituted from template parameters + // and appear as literals in the static assert error. + if (isa<SubstNonTypeTemplateParmExpr>(E)) + return false; + + // -5 is also simple to understand. + if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E)) + return UsefulToPrintExpr(UnaryOp->getSubExpr()); + + // Only print nested arithmetic operators. + if (const auto *BO = dyn_cast<BinaryOperator>(E)) + return (BO->isShiftOp() || BO->isAdditiveOp() || BO->isMultiplicativeOp() || + BO->isBitwiseOp()); + + return true; +} + +/// Try to print more useful information about a failed static_assert +/// with expression \E +void Sema::DiagnoseStaticAssertDetails(const Expr *E) { + if (const auto *Op = dyn_cast<BinaryOperator>(E); + Op && Op->getOpcode() != BO_LOr) { + const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts(); + const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts(); + + // Ignore comparisons of boolean expressions with a boolean literal. + if ((isa<CXXBoolLiteralExpr>(LHS) && RHS->getType()->isBooleanType()) || + (isa<CXXBoolLiteralExpr>(RHS) && LHS->getType()->isBooleanType())) + return; + + // Don't print obvious expressions. + if (!UsefulToPrintExpr(LHS) && !UsefulToPrintExpr(RHS)) + return; + + struct { + const clang::Expr *Cond; + Expr::EvalResult Result; + SmallString<12> ValueString; + bool Print; + } DiagSide[2] = {{LHS, Expr::EvalResult(), {}, false}, + {RHS, Expr::EvalResult(), {}, false}}; + for (unsigned I = 0; I < 2; I++) { + const Expr *Side = DiagSide[I].Cond; + + Side->EvaluateAsRValue(DiagSide[I].Result, Context, true); + + 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) + << DiagSide[0].ValueString << Op->getOpcodeStr() + << DiagSide[1].ValueString << Op->getSourceRange(); + } + } +} + +bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message, + std::string &Result, + ASTContext &Ctx, + bool ErrorOnInvalidMessage) { + assert(Message); + assert(!Message->isTypeDependent() && !Message->isValueDependent() && + "can't evaluate a dependant static assert message"); + + if (const auto *SL = dyn_cast<StringLiteral>(Message)) { + assert(SL->isUnevaluated() && "expected an unevaluated string"); + Result.assign(SL->getString().begin(), SL->getString().end()); + return true; + } + + SourceLocation Loc = Message->getBeginLoc(); + QualType T = Message->getType().getNonReferenceType(); + auto *RD = T->getAsCXXRecordDecl(); + if (!RD) { + Diag(Loc, diag::err_static_assert_invalid_message); + return false; + } + + auto FindMember = [&](StringRef Member, bool &Empty, + bool Diag = false) -> std::optional<LookupResult> { + 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); + if (MemberLookup.empty()) + return std::nullopt; + return std::move(MemberLookup); + }; + + bool SizeNotFound, DataNotFound; + std::optional<LookupResult> SizeMember = FindMember("size", SizeNotFound); + std::optional<LookupResult> DataMember = FindMember("data", DataNotFound); + if (SizeNotFound || DataNotFound) { + Diag(Loc, diag::err_static_assert_missing_member_function) + << ((SizeNotFound && DataNotFound) ? 2 + : SizeNotFound ? 0 + : 1); + return false; + } + + if (!SizeMember || !DataMember) { + if (!SizeMember) + FindMember("size", SizeNotFound, /*Diag=*/true); + if (!DataMember) + FindMember("data", DataNotFound, /*Diag=*/true); + return false; + } + + auto BuildExpr = [&](LookupResult &LR) { + ExprResult Res = BuildMemberReferenceExpr( + Message, Message->getType(), Message->getBeginLoc(), false, + CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, nullptr); + if (Res.isInvalid()) + return ExprError(); + Res = BuildCallExpr(nullptr, Res.get(), Loc, std::nullopt, Loc, nullptr, + false, true); + if (Res.isInvalid()) + return ExprError(); + if (Res.get()->isTypeDependent() || Res.get()->isValueDependent()) + return ExprError(); + return TemporaryMaterializationConversion(Res.get()); + }; + + ExprResult SizeE = BuildExpr(*SizeMember); + ExprResult DataE = BuildExpr(*DataMember); + + QualType SizeT = Context.getSizeType(); + QualType ConstCharPtr = + Context.getPointerType(Context.getConstType(Context.CharTy)); + + ExprResult EvaluatedSize = + SizeE.isInvalid() ? ExprError() + : BuildConvertedConstantExpression( + SizeE.get(), SizeT, CCEK_StaticAssertMessageSize); + if (EvaluatedSize.isInvalid()) { + Diag(Loc, diag::err_static_assert_invalid_mem_fn_ret_ty) << /*size*/ 0; + return false; + } + + ExprResult EvaluatedData = + DataE.isInvalid() + ? ExprError() + : BuildConvertedConstantExpression(DataE.get(), ConstCharPtr, + CCEK_StaticAssertMessageData); + if (EvaluatedData.isInvalid()) { + Diag(Loc, diag::err_static_assert_invalid_mem_fn_ret_ty) << /*data*/ 1; + return false; + } + + if (!ErrorOnInvalidMessage && + Diags.isIgnored(diag::warn_static_assert_message_constexpr, Loc)) + return true; + + Expr::EvalResult Status; + SmallVector<PartialDiagnosticAt, 8> Notes; + Status.Diag = &Notes; + if (!Message->EvaluateCharRangeAsString(Result, EvaluatedSize.get(), + EvaluatedData.get(), Ctx, Status) || + !Notes.empty()) { + Diag(Message->getBeginLoc(), + ErrorOnInvalidMessage ? diag::err_static_assert_message_constexpr + : diag::warn_static_assert_message_constexpr); + for (const auto &Note : Notes) + Diag(Note.first, Note.second); + return !ErrorOnInvalidMessage; + } + return true; } Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, - Expr *AssertExpr, - StringLiteral *AssertMessage, + Expr *AssertExpr, Expr *AssertMessage, SourceLocation RParenLoc, bool Failed) { assert(AssertExpr != nullptr && "Expected non-null condition"); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() && + (!AssertMessage || (!AssertMessage->isTypeDependent() && + !AssertMessage->isValueDependent())) && !Failed) { // In a static_assert-declaration, the constant-expression shall be a // constant expression that can be contextually converted to bool. @@ -16332,18 +17444,48 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, AssertExpr = FullAssertExpr.get(); llvm::APSInt Cond; + Expr *BaseExpr = AssertExpr; + AllowFoldKind FoldKind = NoFold; + + if (!getLangOpts().CPlusPlus) { + // In C mode, allow folding as an extension for better compatibility with + // C++ in terms of expressions like static_assert("test") or + // static_assert(nullptr). + FoldKind = AllowFold; + } + if (!Failed && VerifyIntegerConstantExpression( - AssertExpr, &Cond, - diag::err_static_assert_expression_is_not_constant) - .isInvalid()) + BaseExpr, &Cond, + diag::err_static_assert_expression_is_not_constant, + FoldKind).isInvalid()) Failed = true; - if (!Failed && !Cond) { + // If the static_assert passes, only verify that + // the message is grammatically valid without evaluating it. + if (!Failed && AssertMessage && Cond.getBoolValue()) { + std::string Str; + EvaluateStaticAssertMessageAsString(AssertMessage, Str, Context, + /*ErrorOnInvalidMessage=*/false); + } + + // CWG2518 + // [dcl.pre]/p10 If [...] the expression is evaluated in the context of a + // template definition, the declaration has no effect. + bool InTemplateDefinition = + getLangOpts().CPlusPlus && CurContext->isDependentContext(); + + if (!Failed && !Cond && !InTemplateDefinition) { SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); - if (AssertMessage) - AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy()); - + bool HasMessage = AssertMessage; + if (AssertMessage) { + std::string Str; + HasMessage = + EvaluateStaticAssertMessageAsString( + AssertMessage, Str, Context, /*ErrorOnInvalidMessage=*/true) || + !Str.empty(); + Msg << Str; + } Expr *InnerCond = nullptr; std::string InnerCondDescription; std::tie(InnerCond, InnerCondDescription) = @@ -16351,19 +17493,22 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) { // Drill down into concept specialization expressions to see why they // weren't satisfied. - Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed) + << !HasMessage << Msg.str() << AssertExpr->getSourceRange(); ConstraintSatisfaction Satisfaction; if (!CheckConstraintSatisfaction(InnerCond, Satisfaction)) DiagnoseUnsatisfiedConstraint(Satisfaction); } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) && !isa<IntegerLiteral>(InnerCond)) { - Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed) - << InnerCondDescription << !AssertMessage - << Msg.str() << InnerCond->getSourceRange(); + Diag(InnerCond->getBeginLoc(), + diag::err_static_assert_requirement_failed) + << InnerCondDescription << !HasMessage << Msg.str() + << InnerCond->getSourceRange(); + DiagnoseStaticAssertDetails(InnerCond); } else { - Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed) + << !HasMessage << Msg.str() << AssertExpr->getSourceRange(); + PrintContextStack(); } Failed = true; } @@ -16394,7 +17539,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); QualType T = TSInfo->getType(); - SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange(); + SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); // C++03 [class.friend]p2: // An elaborated-type-specifier shall be used in a friend declaration @@ -16460,12 +17605,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, /// Handle a friend tag declaration where the scope specifier was /// templated. -Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, - unsigned TagSpec, SourceLocation TagLoc, - CXXScopeSpec &SS, IdentifierInfo *Name, - SourceLocation NameLoc, - const ParsedAttributesView &Attr, - MultiTemplateParamsArg TempParamLists) { +DeclResult Sema::ActOnTemplatedFriendTag( + Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool IsMemberSpecialization = false; @@ -16478,7 +17621,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (TemplateParams->size() > 0) { // This is a declaration of a class template. if (Invalid) - return nullptr; + return true; return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, @@ -16493,7 +17636,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, } } - if (Invalid) return nullptr; + if (Invalid) return true; bool isAllExplicitSpecializations = true; for (unsigned I = TempParamLists.size(); I-- > 0; ) { @@ -16512,15 +17655,15 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (SS.isEmpty()) { bool Owned = false; bool IsDependent = false; - return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, - Attr, AS_public, + return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, + AS_public, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, /*ScopedEnumKWLoc=*/SourceLocation(), /*ScopedEnumUsesClassTag=*/false, /*UnderlyingType=*/TypeResult(), /*IsTypeSpecifier=*/false, - /*IsTemplateParamOrArg=*/false); + /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside); } NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); @@ -16529,7 +17672,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc, *Name, NameLoc); if (T.isNull()) - return nullptr; + return true; TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); if (isa<DependentNameType>(T)) { @@ -16627,8 +17770,9 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. - Declarator TheDeclarator(DS, DeclaratorContext::Member); - TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S); + Declarator TheDeclarator(DS, ParsedAttributesView::none(), + DeclaratorContext::Member); + TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator); QualType T = TSI->getType(); if (TheDeclarator.isInvalidType()) return nullptr; @@ -16693,7 +17837,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); SourceLocation Loc = D.getIdentifierLoc(); - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D); // C++ [class.friend]p1 // A friend of a class is a function or class.... @@ -16745,6 +17889,8 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForExternalRedeclaration); + bool isTemplateId = D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId; + // There are five cases here. // - There's no scope specifier and we're in a local class. Only look // for functions declared in the immediately-enclosing block scope. @@ -16782,14 +17928,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, } adjustContextForLocalExternDecl(DC); - // C++ [class.friend]p6: - // A function can be defined in a friend declaration of a class if and - // only if the class is a non-local class (9.8), the function name is - // unqualified, and the function has namespace scope. - if (D.isFunctionDefinition()) { - Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); - } - // - There's no scope specifier, in which case we just go to the // appropriate scope and look for a function or function template // there as appropriate. @@ -16800,8 +17938,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // elaborated-type-specifier, the lookup to determine whether // the entity has been previously declared shall not consider // any scopes outside the innermost enclosing namespace. - bool isTemplateId = - D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId; // Find the appropriate context according to the above. DC = CurContext; @@ -16816,10 +17952,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, while (DC->isRecord()) DC = DC->getParent(); - DeclContext *LookupDC = DC; - while (LookupDC->isTransparentContext()) - LookupDC = LookupDC->getParent(); - + DeclContext *LookupDC = DC->getNonTransparentContext(); while (true) { LookupQualifiedName(Previous, LookupDC); @@ -16857,39 +17990,12 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, diag::warn_cxx98_compat_friend_is_member : diag::err_friend_is_member); - if (D.isFunctionDefinition()) { - // C++ [class.friend]p6: - // A function can be defined in a friend declaration of a class if and - // only if the class is a non-local class (9.8), the function name is - // unqualified, and the function has namespace scope. - // - // FIXME: We should only do this if the scope specifier names the - // innermost enclosing namespace; otherwise the fixit changes the - // meaning of the code. - SemaDiagnosticBuilder DB - = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); - - DB << SS.getScopeRep(); - if (DC->isFileContext()) - DB << FixItHint::CreateRemoval(SS.getRange()); - SS.clear(); - } - // - There's a scope specifier that does not match any template // parameter lists, in which case we use some arbitrary context, // create a method or method template, and wait for instantiation. // - There's a scope specifier that does match some template // parameter lists, which we don't handle right now. } else { - if (D.isFunctionDefinition()) { - // C++ [class.friend]p6: - // A function can be defined in a friend declaration of a class if and - // only if the class is a non-local class (9.8), the function name is - // unqualified, and the function has namespace scope. - Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def) - << SS.getScopeRep(); - } - DC = CurContext; assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?"); } @@ -16974,6 +18080,38 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, else FD = cast<FunctionDecl>(ND); + // C++ [class.friend]p6: + // A function may be defined in a friend declaration of a class if and + // only if the class is a non-local class, and the function name is + // unqualified. + if (D.isFunctionDefinition()) { + // Qualified friend function definition. + if (SS.isNotEmpty()) { + // FIXME: We should only do this if the scope specifier names the + // innermost enclosing namespace; otherwise the fixit changes the + // meaning of the code. + SemaDiagnosticBuilder DB = + Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); + + DB << SS.getScopeRep(); + if (DC->isFileContext()) + DB << FixItHint::CreateRemoval(SS.getRange()); + + // Friend function defined in a local class. + } else if (FunctionContainingLocalClass) { + Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); + + // Per [basic.pre]p4, a template-id is not a name. Therefore, if we have + // a template-id, the function name is not unqualified because these is + // no name. While the wording requires some reading in-between the + // lines, GCC, MSVC, and EDG all consider a friend function + // specialization definitions // to be de facto explicit specialization + // and diagnose them as such. + } else if (isTemplateId) { + Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def); + } + } + // C++11 [dcl.fct.default]p4: If a friend declaration specifies a // default argument expression, that declaration shall be a definition // and shall be the only declaration of the function or function @@ -17088,13 +18226,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { return; } - if (DefKind.isComparison() && - !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { - Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class) - << (int)DefKind.asComparison(); - return; - } - // Issue compatibility warning. We already warned if the operator is // 'operator<=>' when parsing the '<=>' token. if (DefKind.isComparison() && @@ -17106,6 +18237,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { FD->setDefaulted(); FD->setExplicitlyDefaulted(); + FD->setDefaultLoc(DefaultLoc); // Defer checking functions that are defaulted in a dependent context. if (FD->isDependentContext()) @@ -17116,31 +18248,41 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { // that we've marked it as defaulted. FD->setWillHaveBody(false); - // If this definition appears within the record, do the checking when - // the record is complete. This is always the case for a defaulted - // comparison. - if (DefKind.isComparison()) - return; - auto *MD = cast<CXXMethodDecl>(FD); - - const FunctionDecl *Primary = FD; - if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) - // Ask the template instantiation pattern that actually had the - // '= default' on it. - Primary = Pattern; + if (DefKind.isComparison()) { + // If this comparison's defaulting occurs within the definition of its + // lexical class context, we have to do the checking when complete. + if (auto const *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext())) + if (!RD->isCompleteDefinition()) + return; + } - // If the method was defaulted on its first declaration, we will have + // If this member fn was defaulted on its first declaration, we will have // already performed the checking in CheckCompletedCXXClass. Such a // declaration doesn't trigger an implicit definition. - if (Primary->getCanonicalDecl()->isDefaulted()) - return; + if (isa<CXXMethodDecl>(FD)) { + const FunctionDecl *Primary = FD; + if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) + // Ask the template instantiation pattern that actually had the + // '= default' on it. + Primary = Pattern; + if (Primary->getCanonicalDecl()->isDefaulted()) + return; + } - // FIXME: Once we support defining comparisons out of class, check for a - // defaulted comparison here. - if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember())) - MD->setInvalidDecl(); - else - DefineDefaultedFunction(*this, MD, DefaultLoc); + if (DefKind.isComparison()) { + if (CheckExplicitlyDefaultedComparison(nullptr, FD, DefKind.asComparison())) + FD->setInvalidDecl(); + else + DefineDefaultedComparison(DefaultLoc, FD, DefKind.asComparison()); + } else { + auto *MD = cast<CXXMethodDecl>(FD); + + if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember(), + DefaultLoc)) + MD->setInvalidDecl(); + else + DefineDefaultedFunction(*this, MD, DefaultLoc); + } } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { @@ -17162,6 +18304,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { } } +void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc, + FnBodyKind BodyKind) { + switch (BodyKind) { + case FnBodyKind::Delete: + SetDeclDeleted(D, Loc); + break; + case FnBodyKind::Default: + SetDeclDefaulted(D, Loc); + break; + case FnBodyKind::Other: + llvm_unreachable( + "Parsed function body should be '= delete;' or '= default;'"); + } +} + bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old) { const auto *NewFT = New->getType()->castAs<FunctionProtoType>(); @@ -17180,6 +18337,14 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, } } + // SME attributes must match when overriding a function declaration. + if (IsInvalidSMECallConversion(Old->getType(), New->getType())) { + 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>(); @@ -17210,6 +18375,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(); @@ -17327,7 +18506,7 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { Method->setRangeEnd(EndLoc); if (Method->isVirtual() || Method->getParent()->isDependentContext()) { - Method->setPure(); + Method->setIsPureVirtual(); return false; } @@ -17452,7 +18631,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, return; // Do not mark as used if compiling for the device outside of the target // region. - if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice && !isInOpenMPDeclareTargetContext() && !isInOpenMPTargetExecutionDirective()) { if (!DefinitionRequired) @@ -17500,7 +18679,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // immediately. For all other classes, we mark their virtual members // at the end of the translation unit. if (Class->isLocalClass()) - MarkVirtualMembersReferenced(Loc, Class); + MarkVirtualMembersReferenced(Loc, Class->getDefinition()); else VTableUses.push_back(std::make_pair(Class, Loc)); } @@ -17546,7 +18725,7 @@ bool Sema::DefineUsedVTables() { // definition. bool IsExplicitInstantiationDeclaration = ClassTSK == TSK_ExplicitInstantiationDeclaration; - for (auto R : Class->redecls()) { + for (auto *R : Class->redecls()) { TemplateSpecializationKind TSK = cast<CXXRecordDecl>(R)->getTemplateSpecializationKind(); if (TSK == TSK_ExplicitInstantiationDeclaration) @@ -17582,16 +18761,12 @@ bool Sema::DefineUsedVTables() { // no key function or the key function is inlined. Don't warn in C++ ABIs // that lack key functions, since the user won't be able to make one. if (Context.getTargetInfo().getCXXABI().hasKeyFunctions() && - Class->isExternallyVisible() && ClassTSK != TSK_ImplicitInstantiation) { + Class->isExternallyVisible() && ClassTSK != TSK_ImplicitInstantiation && + ClassTSK != TSK_ExplicitInstantiationDefinition) { const FunctionDecl *KeyFunctionDef = nullptr; if (!KeyFunction || (KeyFunction->hasBody(KeyFunctionDef) && - KeyFunctionDef->isInlined())) { - Diag(Class->getLocation(), - ClassTSK == TSK_ExplicitInstantiationDefinition - ? diag::warn_weak_template_vtable - : diag::warn_weak_vtable) - << Class; - } + KeyFunctionDef->isInlined())) + Diag(Class->getLocation(), diag::warn_weak_vtable) << Class; } } VTableUses.clear(); @@ -17602,7 +18777,7 @@ bool Sema::DefineUsedVTables() { void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD) { for (const auto *I : RD->methods()) - if (I->isVirtual() && !I->isPure()) + if (I->isVirtual() && !I->isPureVirtual()) ResolveExceptionSpec(Loc, I->getType()->castAs<FunctionProtoType>()); } @@ -17623,7 +18798,8 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, // C++ [basic.def.odr]p2: // [...] A virtual member function is used if it is not pure. [...] - if (!Overrider->isPure() && (!ConstexprOnly || Overrider->isConstexpr())) + if (!Overrider->isPureVirtual() && + (!ConstexprOnly || Overrider->isConstexpr())) MarkFunctionReferenced(Loc, Overrider); } } @@ -17662,9 +18838,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, None); + InitializationSequence InitSeq(*this, InitEntity, InitKind, std::nullopt); ExprResult MemberInit = - InitSeq.Perform(*this, InitEntity, InitKind, None); + InitSeq.Perform(*this, InitEntity, InitKind, std::nullopt); MemberInit = MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) @@ -17765,8 +18941,8 @@ void Sema::CheckDelegatingCtorCycles() { llvm::SmallPtrSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; for (DelegatingCtorDeclsType::iterator - I = DelegatingCtorDecls.begin(ExternalSource), - E = DelegatingCtorDecls.end(); + I = DelegatingCtorDecls.begin(ExternalSource.get()), + E = DelegatingCtorDecls.end(); I != E; ++I) DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); @@ -17856,7 +19032,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { case EST_NoexceptTrue: if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) return true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case EST_Dynamic: for (const auto &E : Proto->exceptions()) { @@ -17882,27 +19058,27 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { else if (const auto *G = dyn_cast<PtGuardedByAttr>(A)) Arg = G->getArg(); else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A)) - Args = llvm::makeArrayRef(AA->args_begin(), AA->args_size()); + Args = llvm::ArrayRef(AA->args_begin(), AA->args_size()); else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A)) - Args = llvm::makeArrayRef(AB->args_begin(), AB->args_size()); + Args = llvm::ArrayRef(AB->args_begin(), AB->args_size()); else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) { Arg = ETLF->getSuccessValue(); - Args = llvm::makeArrayRef(ETLF->args_begin(), ETLF->args_size()); + Args = llvm::ArrayRef(ETLF->args_begin(), ETLF->args_size()); } else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) { Arg = STLF->getSuccessValue(); - Args = llvm::makeArrayRef(STLF->args_begin(), STLF->args_size()); + Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size()); } else if (const auto *LR = dyn_cast<LockReturnedAttr>(A)) Arg = LR->getArg(); else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A)) - Args = llvm::makeArrayRef(LE->args_begin(), LE->args_size()); + Args = llvm::ArrayRef(LE->args_begin(), LE->args_size()); else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A)) - Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size()); + Args = llvm::ArrayRef(RC->args_begin(), RC->args_size()); else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A)) - Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size()); + Args = llvm::ArrayRef(AC->args_begin(), AC->args_size()); else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A)) - Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size()); + Args = llvm::ArrayRef(AC->args_begin(), AC->args_size()); else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A)) - Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size()); + Args = llvm::ArrayRef(RC->args_begin(), RC->args_size()); if (Arg && !Finder.TraverseStmt(Arg)) return true; @@ -18017,7 +19193,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, } SourceLocation Loc = D.getIdentifierLoc(); - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D); QualType T = TInfo->getType(); if (getLangOpts().CPlusPlus) { CheckExtraCXXDefaultArguments(D); @@ -18112,8 +19288,7 @@ void Sema::ActOnStartFunctionDeclarationDeclarator( } if (ExplicitParams) { Info.AutoTemplateParameterDepth = ExplicitParams->getDepth(); - for (NamedDecl *Param : *ExplicitParams) - Info.TemplateParams.push_back(Param); + llvm::append_range(Info.TemplateParams, *ExplicitParams); Info.NumExplicitTemplateParams = ExplicitParams->size(); } else { Info.AutoTemplateParameterDepth = TemplateParameterDepth; |