diff options
author | Robert Nagy <robert@cvs.openbsd.org> | 2023-03-26 09:09:32 +0000 |
---|---|---|
committer | Robert Nagy <robert@cvs.openbsd.org> | 2023-03-26 09:09:32 +0000 |
commit | 37d96ad1fa72e9ee88c56559856736541a49735f (patch) | |
tree | 809ae57214a454ad42835ece63494e5078c8f24b /gnu | |
parent | 20adf64c6c91b1cb291ab3a7cf0cdc0aae4309b7 (diff) |
allow out-of-class defaulting of comparison operators
ok deraadt@, mortimer@
this is backport of the following upstream commit:
commit 5fbe21a7748f91adbd1b16c95bbfe180642320a3
Author: Nathan Sidwell <nathan@acm.org>
Date: Wed Jun 16 10:43:43 2021 -0700
[clang] p2085 out-of-class comparison operator defaulting
This implements p2085, allowing out-of-class defaulting of comparison
operators, primarily so they need not be inline, IIUC intent. this was
mostly straigh forward, but required reimplementing
Sema::CheckExplicitlyDefaultedComparison, as now there's a case where
we have no a priori clue as to what class a defaulted comparison may
be for. We have to inspect the parameter types to find out. Eg:
class X { ... };
bool operator==(X, X) = default;
Thus reimplemented the parameter type checking, and added 'is this a
friend' functionality for the above case.
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/llvm/clang/include/clang/Basic/DiagnosticSemaKinds.td | 13 | ||||
-rw-r--r-- | gnu/llvm/clang/lib/Sema/SemaDeclCXX.cpp | 2299 |
2 files changed, 1526 insertions, 786 deletions
diff --git a/gnu/llvm/clang/include/clang/Basic/DiagnosticSemaKinds.td b/gnu/llvm/clang/include/clang/Basic/DiagnosticSemaKinds.td index 845c922adb6..f7ed458a2de 100644 --- a/gnu/llvm/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/gnu/llvm/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9100,15 +9100,22 @@ def warn_cxx17_compat_defaulted_comparison : Warning< "before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore; def err_defaulted_comparison_template : Error< "comparison operator template cannot be defaulted">; -def err_defaulted_comparison_out_of_class : Error< - "%sub{select_defaulted_comparison_kind}0 can only be defaulted in a class " - "definition">; +def err_defaulted_comparison_num_args : Error< + "%select{non-member|member}0 %sub{select_defaulted_comparison_kind}1" + " comparison operator must have %select{2|1}0 parameters">; def err_defaulted_comparison_param : Error< "invalid parameter type for defaulted %sub{select_defaulted_comparison_kind}0" "; found %1, expected %2%select{| or %4}3">; +def err_defaulted_comparison_param_unknown : Error< + "invalid parameter type for non-member defaulted" + " %sub{select_defaulted_comparison_kind}0" + "; found %1, expected class or reference to a constant class">; def err_defaulted_comparison_param_mismatch : Error< "parameters for defaulted %sub{select_defaulted_comparison_kind}0 " "must have the same type%diff{ (found $ vs $)|}1,2">; +def err_defaulted_comparison_not_friend : Error< + "%sub{select_defaulted_comparison_kind}0 is not a friend of" + " %select{|incomplete class }1%2">; def err_defaulted_comparison_non_const : Error< "defaulted member %sub{select_defaulted_comparison_kind}0 must be " "const-qualified">; diff --git a/gnu/llvm/clang/lib/Sema/SemaDeclCXX.cpp b/gnu/llvm/clang/lib/Sema/SemaDeclCXX.cpp index 831e55046e8..23020a9c16c 100644 --- a/gnu/llvm/clang/lib/Sema/SemaDeclCXX.cpp +++ b/gnu/llvm/clang/lib/Sema/SemaDeclCXX.cpp @@ -38,8 +38,9 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.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 <map> #include <set> @@ -51,102 +52,109 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - /// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses - /// the default argument of a parameter to determine whether it - /// contains any ill-formed subexpressions. For example, this will - /// diagnose the use of local variables or parameters within the - /// default argument expression. - class CheckDefaultArgumentVisitor - : public StmtVisitor<CheckDefaultArgumentVisitor, bool> { - Expr *DefaultArg; - Sema *S; +/// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses +/// the default argument of a parameter to determine whether it +/// contains any ill-formed subexpressions. For example, this will +/// diagnose the use of local variables or parameters within the +/// default argument expression. +class CheckDefaultArgumentVisitor + : public ConstStmtVisitor<CheckDefaultArgumentVisitor, bool> { + Sema &S; + const Expr *DefaultArg; - public: - CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) - : DefaultArg(defarg), S(s) {} - - bool VisitExpr(Expr *Node); - bool VisitDeclRefExpr(DeclRefExpr *DRE); - bool VisitCXXThisExpr(CXXThisExpr *ThisE); - bool VisitLambdaExpr(LambdaExpr *Lambda); - bool VisitPseudoObjectExpr(PseudoObjectExpr *POE); - }; +public: + CheckDefaultArgumentVisitor(Sema &S, const Expr *DefaultArg) + : S(S), DefaultArg(DefaultArg) {} + + bool VisitExpr(const Expr *Node); + bool VisitDeclRefExpr(const DeclRefExpr *DRE); + bool VisitCXXThisExpr(const CXXThisExpr *ThisE); + bool VisitLambdaExpr(const LambdaExpr *Lambda); + bool VisitPseudoObjectExpr(const PseudoObjectExpr *POE); +}; - /// VisitExpr - Visit all of the children of this expression. - bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) { - bool IsInvalid = false; - for (Stmt *SubStmt : Node->children()) - IsInvalid |= Visit(SubStmt); - return IsInvalid; - } - - /// VisitDeclRefExpr - Visit a reference to a declaration, to - /// determine whether this declaration can be used in the default - /// argument expression. - bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { - NamedDecl *Decl = DRE->getDecl(); - if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(Decl)) { - // C++ [dcl.fct.default]p9 - // Default arguments are evaluated each time the function is - // called. The order of evaluation of function arguments is - // unspecified. Consequently, parameters of a function shall not - // be used in default argument expressions, even if they are not - // evaluated. Parameters of a function declared before a default - // argument expression are in scope and can hide namespace and - // class member names. - return S->Diag(DRE->getBeginLoc(), - diag::err_param_default_argument_references_param) +/// VisitExpr - Visit all of the children of this expression. +bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) { + bool IsInvalid = false; + for (const Stmt *SubStmt : Node->children()) + IsInvalid |= Visit(SubStmt); + return IsInvalid; +} + +/// VisitDeclRefExpr - Visit a reference to a declaration, to +/// determine whether this declaration can be used in the default +/// argument expression. +bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { + const NamedDecl *Decl = DRE->getDecl(); + if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) { + // C++ [dcl.fct.default]p9: + // [...] parameters of a function shall not be used in default + // argument expressions, even if they are not evaluated. [...] + // + // C++17 [dcl.fct.default]p9 (by CWG 2082): + // [...] A parameter shall not appear as a potentially-evaluated + // expression in a default argument. [...] + // + if (DRE->isNonOdrUse() != NOUR_Unevaluated) + return S.Diag(DRE->getBeginLoc(), + diag::err_param_default_argument_references_param) << Param->getDeclName() << DefaultArg->getSourceRange(); - } else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) { - // C++ [dcl.fct.default]p7 - // Local variables shall not be used in default argument - // expressions. - if (VDecl->isLocalVarDecl()) - return S->Diag(DRE->getBeginLoc(), - diag::err_param_default_argument_references_local) - << VDecl->getDeclName() << DefaultArg->getSourceRange(); - } - - return false; - } - - /// VisitCXXThisExpr - Visit a C++ "this" expression. - bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(CXXThisExpr *ThisE) { - // C++ [dcl.fct.default]p8: - // The keyword this shall not be used in a default argument of a - // member function. - return S->Diag(ThisE->getBeginLoc(), - diag::err_param_default_argument_references_this) - << ThisE->getSourceRange(); + } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) { + // C++ [dcl.fct.default]p7: + // Local variables shall not be used in default argument + // expressions. + // + // C++17 [dcl.fct.default]p7 (by CWG 2082): + // A local variable shall not appear as a potentially-evaluated + // 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. + // + if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse()) + return S.Diag(DRE->getBeginLoc(), + diag::err_param_default_argument_references_local) + << VDecl->getDeclName() << DefaultArg->getSourceRange(); } - bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *POE) { - bool Invalid = false; - for (PseudoObjectExpr::semantics_iterator - i = POE->semantics_begin(), e = POE->semantics_end(); i != e; ++i) { - Expr *E = *i; + return false; +} - // Look through bindings. - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { - E = OVE->getSourceExpr(); - assert(E && "pseudo-object binding without source expression?"); - } +/// VisitCXXThisExpr - Visit a C++ "this" expression. +bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(const CXXThisExpr *ThisE) { + // C++ [dcl.fct.default]p8: + // The keyword this shall not be used in a default argument of a + // member function. + return S.Diag(ThisE->getBeginLoc(), + diag::err_param_default_argument_references_this) + << ThisE->getSourceRange(); +} - Invalid |= Visit(E); +bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr( + const PseudoObjectExpr *POE) { + bool Invalid = false; + for (const Expr *E : POE->semantics()) { + // Look through bindings. + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) { + E = OVE->getSourceExpr(); + assert(E && "pseudo-object binding without source expression?"); } - return Invalid; + + Invalid |= Visit(E); } + return Invalid; +} - bool CheckDefaultArgumentVisitor::VisitLambdaExpr(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; +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); - } + return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg); } +} // namespace void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, @@ -246,14 +254,11 @@ void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) { ComputedEST = EST_None; } -bool -Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, - SourceLocation EqualLoc) { +ExprResult Sema::ConvertParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, + SourceLocation EqualLoc) { if (RequireCompleteType(Param->getLocation(), Param->getType(), - diag::err_typecheck_decl_incomplete_type)) { - Param->setInvalidDecl(); + diag::err_typecheck_decl_incomplete_type)) return true; - } // C++ [dcl.fct.default]p5 // A default argument expression is implicitly converted (clause @@ -274,7 +279,12 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, CheckCompletedExpr(Arg, EqualLoc); Arg = MaybeCreateExprWithCleanups(Arg); - // Okay: add the default argument to the parameter + return Arg; +} + +void Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, + SourceLocation EqualLoc) { + // Add the default argument to the parameter Param->setDefaultArg(Arg); // We have already instantiated this parameter; provide each of the @@ -288,8 +298,6 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, // We're done tracking this parameter's instantiations. UnparsedDefaultArgInstantiations.erase(InstPos); } - - return false; } /// ActOnParamDefaultArgument - Check whether the default argument @@ -304,18 +312,22 @@ 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(); - Param->setInvalidDecl(); - return; + return Fail(); } // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) { - Param->setInvalidDecl(); - return; + return Fail(); } // C++11 [dcl.fct.default]p3 @@ -324,15 +336,21 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, if (Param->isParameterPack()) { Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack) << DefaultArg->getSourceRange(); + // Recover by discarding the default argument. + Param->setDefaultArg(nullptr); return; } + ExprResult Result = ConvertParamDefaultArgument(Param, DefaultArg, EqualLoc); + if (Result.isInvalid()) + return Fail(); + + DefaultArg = Result.getAs<Expr>(); + // Check that the default argument is well-formed - CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this); - if (DefaultArgChecker.Visit(DefaultArg)) { - Param->setInvalidDecl(); - return; - } + CheckDefaultArgumentVisitor DefaultArgChecker(*this, DefaultArg); + if (DefaultArgChecker.Visit(DefaultArg)) + return Fail(); SetParamDefaultArgument(Param, DefaultArg, EqualLoc); } @@ -362,10 +380,8 @@ void Sema::ActOnParamDefaultArgumentError(Decl *param, ParmVarDecl *Param = cast<ParmVarDecl>(param); Param->setInvalidDecl(); UnparsedDefaultArgLocs.erase(Param); - Param->setDefaultArg(new(Context) - OpaqueValueExpr(EqualLoc, - Param->getType().getNonReferenceType(), - VK_RValue)); + Param->setDefaultArg(new (Context) OpaqueValueExpr( + EqualLoc, Param->getType().getNonReferenceType(), VK_PRValue)); } /// CheckExtraCXXDefaultArguments - Check for any extra default @@ -419,14 +435,9 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { } static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) { - for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) { - const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1); - if (!PVD->hasDefaultArg()) - return false; - if (!PVD->hasInheritedDefaultArg()) - return true; - } - return false; + return std::any_of(FD->param_begin(), FD->param_end(), [](ParmVarDecl *P) { + return P->hasDefaultArg() && !P->hasInheritedDefaultArg(); + }); } /// MergeCXXFunctionDecl - Merge two declarations of the same C++ @@ -641,7 +652,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // contain the constexpr specifier. if (New->getConstexprKind() != Old->getConstexprKind()) { Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) - << New << New->getConstexprKind() << Old->getConstexprKind(); + << New << static_cast<int>(New->getConstexprKind()) + << static_cast<int>(Old->getConstexprKind()); Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && @@ -664,7 +676,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // for the same class template shall not have equivalent // parameter-declaration-clauses. if (isa<CXXDeductionGuideDecl>(New) && - !New->isFunctionTemplateSpecialization()) { + !New->isFunctionTemplateSpecialization() && isVisible(Old)) { Diag(New->getLocation(), diag::err_deduction_guide_redeclared); Diag(Old->getLocation(), diag::note_previous_declaration); } @@ -680,6 +692,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Invalid = true; } + // C++11 [temp.friend]p4 (DR329): + // When a function is defined in a friend function declaration in a class + // template, the function is instantiated when the function is odr-used. + // The same restrictions on multiple declarations and definitions that + // apply to non-template function declarations and definitions also apply + // to these implicit definitions. + const FunctionDecl *OldDefinition = nullptr; + if (New->isThisDeclarationInstantiatedFromAFriendDefinition() && + Old->isDefined(OldDefinition, true)) + CheckForFunctionRedefinition(New, OldDefinition); + return Invalid; } @@ -709,7 +732,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Diag(Decomp.getLSquareLoc(), !getLangOpts().CPlusPlus17 ? diag::ext_decomp_decl - : D.getContext() == DeclaratorContext::ConditionContext + : D.getContext() == DeclaratorContext::Condition ? diag::ext_decomp_decl_cond : diag::warn_cxx14_compat_decomp_decl) << Decomp.getSourceRange(); @@ -761,7 +784,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Err << SourceRange(Loc, Loc); } else if (!CPlusPlus20Specifiers.empty()) { auto &&Warn = Diag(CPlusPlus20SpecifierLocs.front(), - getLangOpts().CPlusPlus2a + getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_decomp_decl_spec : diag::ext_decomp_decl_spec); Warn << (int)CPlusPlus20Specifiers.size() @@ -778,7 +801,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // C++2a [dcl.struct.bind]p1: // A cv that includes volatile is deprecated if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) && - getLangOpts().CPlusPlus2a) + getLangOpts().CPlusPlus20) Diag(DS.getVolatileSpecLoc(), diag::warn_deprecated_volatile_structured_binding); @@ -831,17 +854,25 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Previous.clear(); } + auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); + + // Find the shadowed declaration before filtering for scope. + NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() + ? getShadowedDeclaration(BD, Previous) + : nullptr; + bool ConsiderLinkage = DC->isFunctionOrMethod() && DS.getStorageClassSpec() == DeclSpec::SCS_extern; FilterLookupForScope(Previous, DC, S, ConsiderLinkage, /*AllowInlineNamespace*/false); + if (!Previous.empty()) { 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); } - - auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); PushOnScopeChains(BD, S, true); Bindings.push_back(BD); ParsingInitForAutoVars.insert(BD); @@ -876,8 +907,9 @@ static bool checkSimpleDecomposition( llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) { if ((int64_t)Bindings.size() != NumElems) { S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() << NumElems.toString(10) - << (NumElems < Bindings.size()); + << DecompType << (unsigned)Bindings.size() + << (unsigned)NumElems.getLimitedValue(UINT_MAX) + << toString(NumElems, 10) << (NumElems < Bindings.size()); return true; } @@ -942,17 +974,22 @@ static bool checkComplexDecomposition(Sema &S, } static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, - TemplateArgumentListInfo &Args) { + TemplateArgumentListInfo &Args, + const TemplateParameterList *Params) { SmallString<128> SS; llvm::raw_svector_ostream OS(SS); bool First = true; + unsigned I = 0; for (auto &Arg : Args.arguments()) { if (!First) OS << ", "; - Arg.getArgument().print(PrintingPolicy, OS); + Arg.getArgument().print( + PrintingPolicy, OS, + TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); First = false; + I++; } - return OS.str(); + return std::string(OS.str()); } static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup, @@ -962,7 +999,7 @@ static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup, auto DiagnoseMissing = [&] { if (DiagID) S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.getPrintingPolicy(), - Args); + Args, /*Params*/ nullptr); return true; }; @@ -1000,7 +1037,8 @@ static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup, if (DiagID) S.RequireCompleteType( Loc, TraitTy, DiagID, - printTemplateArgs(S.Context.getPrintingPolicy(), Args)); + printTemplateArgs(S.Context.getPrintingPolicy(), Args, + TraitTD->getTemplateParameters())); return true; } @@ -1052,9 +1090,11 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, TemplateArgumentListInfo &Args; ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args) : R(R), Args(Args) {} - void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) { - S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) - << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + Sema::SemaDiagnosticBuilder diagnoseNotICE(Sema &S, + SourceLocation Loc) override { + return S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) + << printTemplateArgs(S.Context.getPrintingPolicy(), Args, + /*Params*/ nullptr); } } Diagnoser(R, Args); @@ -1063,7 +1103,7 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, if (E.isInvalid()) return IsTupleLike::Error; - E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser, false); + E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser); if (E.isInvalid()) return IsTupleLike::Error; @@ -1090,7 +1130,8 @@ static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, if (!TD) { R.suppressDiagnostics(); S.Diag(Loc, diag::err_decomp_decl_std_tuple_element_not_specialized) - << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + << printTemplateArgs(S.Context.getPrintingPolicy(), Args, + /*Params*/ nullptr); if (!R.empty()) S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at); return QualType(); @@ -1100,16 +1141,17 @@ static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, } namespace { -struct BindingDiagnosticTrap { +struct InitializingBinding { Sema &S; - DiagnosticErrorTrap Trap; - BindingDecl *BD; - - BindingDiagnosticTrap(Sema &S, BindingDecl *BD) - : S(S), Trap(S.Diags), BD(BD) {} - ~BindingDiagnosticTrap() { - if (Trap.hasErrorOccurred()) - S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD; + InitializingBinding(Sema &S, BindingDecl *BD) : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::InitializingStructuredBinding; + Ctx.PointOfInstantiation = BD->getLocation(); + Ctx.Entity = BD; + S.pushCodeSynthesisContext(Ctx); + } + ~InitializingBinding() { + S.popCodeSynthesisContext(); } }; } @@ -1120,8 +1162,9 @@ static bool checkTupleLikeDecomposition(Sema &S, const llvm::APSInt &TupleSize) { if ((int64_t)Bindings.size() != TupleSize) { S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() << TupleSize.toString(10) - << (TupleSize < Bindings.size()); + << DecompType << (unsigned)Bindings.size() + << (unsigned)TupleSize.getLimitedValue(UINT_MAX) + << toString(TupleSize, 10) << (TupleSize < Bindings.size()); return true; } @@ -1158,7 +1201,7 @@ static bool checkTupleLikeDecomposition(Sema &S, unsigned I = 0; for (auto *B : Bindings) { - BindingDiagnosticTrap Trap(S, B); + InitializingBinding InitContext(S, B); SourceLocation Loc = B->getLocation(); ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); @@ -1169,7 +1212,8 @@ static bool checkTupleLikeDecomposition(Sema &S, // an xvalue otherwise if (!Src->getType()->isLValueReferenceType()) E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), CK_NoOp, - E.get(), nullptr, VK_XValue); + E.get(), nullptr, VK_XValue, + FPOptionsOverride()); TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument( @@ -1233,8 +1277,7 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; RefVD->setInit(E.get()); - if (!E.get()->isValueDependent()) - RefVD->checkInitIsICE(); + S.CheckCompleteVariableDeclaration(RefVD); E = S.BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(B->getDeclName(), Loc), @@ -1345,7 +1388,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, [](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 + << DecompType << (unsigned)Bindings.size() << NumFields << NumFields << (NumFields < Bindings.size()); return true; }; @@ -1358,11 +1401,23 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, if (FD->isUnnamedBitfield()) continue; - if (FD->isAnonymousStructOrUnion()) { - S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) - << DecompType << FD->getType()->isUnionType(); - S.Diag(FD->getLocation(), diag::note_declared_at); - return true; + // All the non-static data members are required to be nameable, so they + // must all have names. + if (!FD->getDeclName()) { + if (RD->isLambda()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_lambda); + S.Diag(RD->getLocation(), diag::note_lambda_decl); + return true; + } + + if (FD->isAnonymousStructOrUnion()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) + << DecompType << FD->getType()->isUnionType(); + S.Diag(FD->getLocation(), diag::note_declared_at); + return true; + } + + // FIXME: Are there any other ways we could have an anonymous member? } // We have a real field to bind. @@ -1528,25 +1583,34 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) { /// [dcl.fct.default]. void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { unsigned NumParams = FD->getNumParams(); - unsigned p; + unsigned ParamIdx = 0; + + // This checking doesn't make sense for explicit specializations; their + // default arguments are determined by the declaration we're specializing, + // not by FD. + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + if (auto *FTD = FD->getDescribedFunctionTemplate()) + if (FTD->isMemberSpecialization()) + return; // Find first parameter with a default argument - for (p = 0; p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); + for (; ParamIdx < NumParams; ++ParamIdx) { + ParmVarDecl *Param = FD->getParamDecl(ParamIdx); if (Param->hasDefaultArg()) break; } - // C++11 [dcl.fct.default]p4: + // C++20 [dcl.fct.default]p4: // In a given function declaration, each parameter subsequent to a parameter // with a default argument shall have a default argument supplied in this or - // a previous declaration or shall be a function parameter pack. A default - // argument shall not be redefined by a later declaration (not even to the - // same value). - unsigned LastMissingDefaultArg = 0; - for (; p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - if (!Param->hasDefaultArg() && !Param->isParameterPack()) { + // a previous declaration, unless the parameter was expanded from a + // parameter pack, or shall be a function parameter pack. + for (; ParamIdx < NumParams; ++ParamIdx) { + ParmVarDecl *Param = FD->getParamDecl(ParamIdx); + if (!Param->hasDefaultArg() && !Param->isParameterPack() && + !(CurrentInstantiationScope && + CurrentInstantiationScope->isLocalPackExpansion(Param))) { if (Param->isInvalidDecl()) /* We already complained about this parameter. */; else if (Param->getIdentifier()) @@ -1556,21 +1620,6 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { else Diag(Param->getLocation(), diag::err_param_default_argument_missing); - - LastMissingDefaultArg = p; - } - } - - if (LastMissingDefaultArg > 0) { - // Some default arguments were missing. Clear out all of the - // default arguments up to (and including) the last missing - // default argument, so that we leave the function parameters - // in a semantically valid state. - for (p = 0; p <= LastMissingDefaultArg; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - if (Param->hasDefaultArg()) { - Param->setDefaultArg(nullptr); - } } } } @@ -1609,7 +1658,7 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject) - << DD->getConstexprKind() << !FD + << static_cast<int>(DD->getConstexprKind()) << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T; SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject) << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T; @@ -1716,7 +1765,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, // - it shall not be virtual; (removed in C++20) const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD); if (Method && Method->isVirtual()) { - if (getLangOpts().CPlusPlus2a) { + if (getLangOpts().CPlusPlus20) { if (Kind == CheckConstexprKind::Diagnose) Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual); } else { @@ -1784,9 +1833,11 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::UsingDirective: case Decl::UnresolvedUsingTypename: case Decl::UnresolvedUsingValue: + case Decl::UsingEnum: // - static_assert-declarations // - using-declarations, // - using-directives, + // - using-enum-declaration continue; case Decl::Typedef: @@ -1856,11 +1907,11 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag( VD->getLocation(), - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_local_var_no_init : diag::ext_constexpr_local_var_no_init) << isa<CXXConstructorDecl>(Dcl); - } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } continue; @@ -1919,7 +1970,7 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef, Sema::CheckConstexprKind Kind) { // In C++20 onwards, there's nothing to check for validity. if (Kind == Sema::CheckConstexprKind::CheckValid && - SemaRef.getLangOpts().CPlusPlus2a) + SemaRef.getLangOpts().CPlusPlus20) return true; if (Field->isInvalidDecl()) @@ -1941,14 +1992,14 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef, if (Kind == Sema::CheckConstexprKind::Diagnose) { if (!Diagnosed) { SemaRef.Diag(Dcl->getLocation(), - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_ctor_missing_init : diag::ext_constexpr_ctor_missing_init); Diagnosed = true; } SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init); - } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } } else if (Field->isAnonymousStructOrUnion()) { @@ -2132,14 +2183,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, // apply the general constexpr rules. switch (Kind) { case Sema::CheckConstexprKind::CheckValid: - if (!SemaRef.getLangOpts().CPlusPlus2a) + if (!SemaRef.getLangOpts().CPlusPlus20) return false; break; case Sema::CheckConstexprKind::Diagnose: SemaRef.Diag(Body->getBeginLoc(), - !SemaRef.getLangOpts().CPlusPlus2a - ? diag::ext_constexpr_function_try_block_cxx2a + !SemaRef.getLangOpts().CPlusPlus20 + ? diag::ext_constexpr_function_try_block_cxx20 : diag::warn_cxx17_compat_constexpr_function_try_block) << isa<CXXConstructorDecl>(Dcl); break; @@ -2162,14 +2213,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, 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().CPlusPlus2a) || + if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) || (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) return false; } else if (Cxx2aLoc.isValid()) { SemaRef.Diag(Cxx2aLoc, - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_body_invalid_stmt - : diag::ext_constexpr_body_invalid_stmt_cxx2a) + : diag::ext_constexpr_body_invalid_stmt_cxx20) << isa<CXXConstructorDecl>(Dcl); } else if (Cxx1yLoc.isValid()) { SemaRef.Diag(Cxx1yLoc, @@ -2194,10 +2245,10 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag( Dcl->getLocation(), - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init : diag::ext_constexpr_union_ctor_no_init); - } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } } @@ -2306,7 +2357,7 @@ 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); + << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval(); 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 @@ -2417,7 +2468,10 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) { QualType BaseType = TInfo->getType(); - + if (BaseType->containsErrors()) { + // Already emitted a diagnostic when parsing the error type. + return nullptr; + } // C++ [class.union]p1: // A union shall not have base classes. if (Class->isUnion()) { @@ -2454,6 +2508,14 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } } + // Make sure that we don't make an ill-formed AST where the type of the + // Class is non-dependent and its attached base class specifier is an + // dependent type, which violates invariants in many clang code paths (e.g. + // constexpr evaluator). If this case happens (in errory-recovery mode), we + // explicitly mark the Class decl invalid. The diagnostic was already + // emitted. + if (!Class->getTypeForDecl()->isDependentType()) + Class->setInvalidDecl(); return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, Access, TInfo, EllipsisLoc); @@ -2576,7 +2638,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute ? (unsigned)diag::warn_unknown_attribute_ignored : (unsigned)diag::err_base_specifier_attribute) - << AL; + << AL << AL.getRange(); } TypeSourceInfo *TInfo = nullptr; @@ -2821,13 +2883,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, /// if there is an error, and Range is the source range to highlight /// if there is an error. /// -/// If either InaccessibleBaseID or AmbigiousBaseConvID are 0, then the +/// If either InaccessibleBaseID or AmbiguousBaseConvID are 0, then the /// diagnostic for the respective type of error will be suppressed, but the /// check for ill-formed code will still be performed. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, - unsigned AmbigiousBaseConvID, + unsigned AmbiguousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath, @@ -2853,7 +2915,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, for (const CXXBasePath &PossiblePath : Paths) { if (PossiblePath.size() == 1) { Path = &PossiblePath; - if (AmbigiousBaseConvID) + if (AmbiguousBaseConvID) Diag(Loc, diag::ext_ms_ambiguous_direct_base) << Base << Derived << Range; break; @@ -2881,7 +2943,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, return false; } - if (AmbigiousBaseConvID) { + if (AmbiguousBaseConvID) { // We know that the derived-to-base conversion is ambiguous, and // we're going to produce a diagnostic. Perform the derived-to-base // search just one more time to compute all of the possible paths so @@ -2900,7 +2962,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, // to each base class subobject. std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); - Diag(Loc, AmbigiousBaseConvID) + Diag(Loc, AmbiguousBaseConvID) << Derived << Base << PathDisplayStr << Range << Name; } return true; @@ -3033,7 +3095,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) { << MD->getDeclName(); } -void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { +void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D, bool Inconsistent) { if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>()) return; CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); @@ -3049,12 +3111,22 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { return; if (MD->size_overridden_methods() > 0) { - unsigned DiagID = isa<CXXDestructorDecl>(MD) - ? diag::warn_destructor_marked_not_override_overriding - : diag::warn_function_marked_not_override_overriding; - Diag(MD->getLocation(), DiagID) << MD->getDeclName(); - const CXXMethodDecl *OMD = *MD->begin_overridden_methods(); - Diag(OMD->getLocation(), diag::note_overridden_virtual_function); + auto EmitDiag = [&](unsigned DiagInconsistent, unsigned DiagSuggest) { + unsigned DiagID = + Inconsistent && !Diags.isIgnored(DiagInconsistent, MD->getLocation()) + ? DiagInconsistent + : DiagSuggest; + Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + const CXXMethodDecl *OMD = *MD->begin_overridden_methods(); + Diag(OMD->getLocation(), diag::note_overridden_virtual_function); + }; + if (isa<CXXDestructorDecl>(MD)) + EmitDiag( + diag::warn_inconsistent_destructor_marked_not_override_overriding, + diag::warn_suggest_destructor_marked_not_override_overriding); + else + EmitDiag(diag::warn_inconsistent_function_marked_not_override_overriding, + diag::warn_suggest_function_marked_not_override_overriding); } } @@ -3555,8 +3627,10 @@ namespace { Base = SubME->getBase(); } - if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts())) + if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts())) { + Visit(Base); return; + } if (AddressOf && AllPODFields) return; @@ -3883,9 +3957,22 @@ void Sema::ActOnStartTrailingRequiresClause(Scope *S, Declarator &D) { } ExprResult Sema::ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr) { + return ActOnRequiresClause(ConstraintExpr); +} + +ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) { + if (ConstraintExpr.isInvalid()) + return ExprError(); + + ConstraintExpr = CorrectDelayedTyposInExpr(ConstraintExpr); if (ConstraintExpr.isInvalid()) return ExprError(); - return CorrectDelayedTyposInExpr(ConstraintExpr); + + if (DiagnoseUnexpandedParameterPack(ConstraintExpr.get(), + UPPC_RequiresClause)) + return ExprError(); + + return ConstraintExpr; } /// This is invoked after parsing an in-class initializer for a @@ -4058,13 +4145,9 @@ ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, IdentifierInfo *MemberOrBase) { if (SS.getScopeRep() || TemplateTypeTy) return nullptr; - DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); - if (Result.empty()) - return nullptr; - ValueDecl *Member; - if ((Member = dyn_cast<FieldDecl>(Result.front())) || - (Member = dyn_cast<IndirectFieldDecl>(Result.front()))) - return Member; + for (auto *D : ClassDecl->lookup(MemberOrBase)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) + return cast<ValueDecl>(D); return nullptr; } @@ -5167,6 +5250,20 @@ static const void *GetKeyForMember(ASTContext &Context, return Member->getAnyMember()->getCanonicalDecl(); } +static void AddInitializerToDiag(const Sema::SemaDiagnosticBuilder &Diag, + const CXXCtorInitializer *Previous, + const CXXCtorInitializer *Current) { + if (Previous->isAnyMemberInitializer()) + Diag << 0 << Previous->getAnyMember(); + else + Diag << 1 << Previous->getTypeSourceInfo()->getType(); + + if (Current->isAnyMemberInitializer()) + Diag << 0 << Current->getAnyMember(); + else + Diag << 1 << Current->getTypeSourceInfo()->getType(); +} + static void DiagnoseBaseOrMemInitializerOrder( Sema &SemaRef, const CXXConstructorDecl *Constructor, ArrayRef<CXXCtorInitializer *> Inits) { @@ -5216,10 +5313,15 @@ static void DiagnoseBaseOrMemInitializerOrder( unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; - CXXCtorInitializer *PrevInit = nullptr; + // Track initializers that are in an incorrect order for either a warning or + // note if multiple ones occur. + SmallVector<unsigned> WarnIndexes; + // Correlates the index of an initializer in the init-list to the index of + // the field/base in the class. + SmallVector<std::pair<unsigned, unsigned>, 32> CorrelatedInitOrder; + for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) { - CXXCtorInitializer *Init = Inits[InitIndex]; - const void *InitKey = GetKeyForMember(SemaRef.Context, Init); + const void *InitKey = GetKeyForMember(SemaRef.Context, Inits[InitIndex]); // Scan forward to try to find this initializer in the idealized // initializers list. @@ -5230,20 +5332,8 @@ static void DiagnoseBaseOrMemInitializerOrder( // If we didn't find this initializer, it must be because we // scanned past it on a previous iteration. That can only // happen if we're out of order; emit a warning. - if (IdealIndex == NumIdealInits && PrevInit) { - Sema::SemaDiagnosticBuilder D = - SemaRef.Diag(PrevInit->getSourceLocation(), - diag::warn_initializer_out_of_order); - - if (PrevInit->isAnyMemberInitializer()) - D << 0 << PrevInit->getAnyMember()->getDeclName(); - else - D << 1 << PrevInit->getTypeSourceInfo()->getType(); - - if (Init->isAnyMemberInitializer()) - D << 0 << Init->getAnyMember()->getDeclName(); - else - D << 1 << Init->getTypeSourceInfo()->getType(); + if (IdealIndex == NumIdealInits && InitIndex) { + WarnIndexes.push_back(InitIndex); // Move back to the initializer's location in the ideal list. for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex) @@ -5253,8 +5343,54 @@ static void DiagnoseBaseOrMemInitializerOrder( assert(IdealIndex < NumIdealInits && "initializer not found in initializer list"); } + CorrelatedInitOrder.emplace_back(IdealIndex, InitIndex); + } - PrevInit = Init; + if (WarnIndexes.empty()) + return; + + // Sort based on the ideal order, first in the pair. + llvm::sort(CorrelatedInitOrder, + [](auto &LHS, auto &RHS) { return LHS.first < RHS.first; }); + + // Introduce a new scope as SemaDiagnosticBuilder needs to be destroyed to + // emit the diagnostic before we can try adding notes. + { + Sema::SemaDiagnosticBuilder D = SemaRef.Diag( + Inits[WarnIndexes.front() - 1]->getSourceLocation(), + WarnIndexes.size() == 1 ? diag::warn_initializer_out_of_order + : diag::warn_some_initializers_out_of_order); + + for (unsigned I = 0; I < CorrelatedInitOrder.size(); ++I) { + if (CorrelatedInitOrder[I].second == I) + continue; + // Ideally we would be using InsertFromRange here, but clang doesn't + // appear to handle InsertFromRange correctly when the source range is + // modified by another fix-it. + D << FixItHint::CreateReplacement( + Inits[I]->getSourceRange(), + Lexer::getSourceText( + CharSourceRange::getTokenRange( + Inits[CorrelatedInitOrder[I].second]->getSourceRange()), + SemaRef.getSourceManager(), SemaRef.getLangOpts())); + } + + // If there is only 1 item out of order, the warning expects the name and + // type of each being added to it. + if (WarnIndexes.size() == 1) { + AddInitializerToDiag(D, Inits[WarnIndexes.front() - 1], + Inits[WarnIndexes.front()]); + return; + } + } + // More than 1 item to warn, create notes letting the user know which ones + // are bad. + for (unsigned WarnIndex : WarnIndexes) { + const clang::CXXCtorInitializer *PrevInit = Inits[WarnIndex - 1]; + auto D = SemaRef.Diag(PrevInit->getSourceLocation(), + diag::note_initializer_out_of_order); + AddInitializerToDiag(D, PrevInit, Inits[WarnIndex]); + D << PrevInit->getSourceRange(); } } @@ -5322,7 +5458,7 @@ bool CheckRedundantUnionInit(Sema &S, return false; } -} +} // namespace /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(Decl *ConstructorDecl, @@ -5443,12 +5579,22 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, // subobjects. bool VisitVirtualBases = !ClassDecl->isAbstract(); + // If the destructor exists and has already been marked used in the MS ABI, + // then virtual base destructors have already been checked and marked used. + // Skip checking them again to avoid duplicate diagnostics. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + CXXDestructorDecl *Dtor = ClassDecl->getDestructor(); + if (Dtor && Dtor->isUsed()) + VisitVirtualBases = false; + } + llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; // Bases. for (const auto &Base : ClassDecl->bases()) { - // Bases are always records in a well-formed non-dependent class. const RecordType *RT = Base.getType()->getAs<RecordType>(); + if (!RT) + continue; // Remember direct virtual bases. if (Base.isVirtual()) { @@ -5477,16 +5623,21 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, DiagnoseUseOfDecl(Dtor, Location); } - if (!VisitVirtualBases) - return; + if (VisitVirtualBases) + MarkVirtualBaseDestructorsReferenced(Location, ClassDecl, + &DirectVirtualBases); +} +void Sema::MarkVirtualBaseDestructorsReferenced( + SourceLocation Location, CXXRecordDecl *ClassDecl, + llvm::SmallPtrSetImpl<const RecordType *> *DirectVirtualBases) { // Virtual bases. for (const auto &VBase : ClassDecl->vbases()) { // Bases are always records in a well-formed non-dependent class. const RecordType *RT = VBase.getType()->castAs<RecordType>(); - // Ignore direct virtual bases. - if (DirectVirtualBases.count(RT)) + // Ignore already visited direct virtual bases. + if (DirectVirtualBases && DirectVirtualBases->count(RT)) continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); @@ -5788,6 +5939,23 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // declaration. return; + // Add a context note to explain how we got to any diagnostics produced below. + struct MarkingClassDllexported { + Sema &S; + MarkingClassDllexported(Sema &S, CXXRecordDecl *Class, + SourceLocation AttrLoc) + : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::MarkingClassDllexported; + Ctx.PointOfInstantiation = AttrLoc; + Ctx.Entity = Class; + S.pushCodeSynthesisContext(Ctx); + } + ~MarkingClassDllexported() { + S.popCodeSynthesisContext(); + } + } MarkingDllexportedContext(S, Class, ClassAttr->getLocation()); + if (S.Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) S.MarkVTableUsed(Class->getLocation(), Class, true); @@ -5816,20 +5984,23 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // The function will be passed to the consumer when its definition is // encountered. - } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || + } 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, explicitly - // defaulted 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. - DiagnosticErrorTrap Trap(S.Diags); + // 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); - if (Trap.hasErrorOccurred()) { - S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class) - << Class << !S.getLangOpts().CPlusPlus11; - break; - } // There is no later point when we will see the definition of this // function, so pass it to the consumer now. @@ -5877,6 +6048,123 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S, } } +static void checkCUDADeviceBuiltinSurfaceClassTemplate(Sema &S, + CXXRecordDecl *Class) { + bool ErrorReported = false; + auto reportIllegalClassTemplate = [&ErrorReported](Sema &S, + ClassTemplateDecl *TD) { + if (ErrorReported) + return; + S.Diag(TD->getLocation(), + diag::err_cuda_device_builtin_surftex_cls_template) + << /*surface*/ 0 << TD; + ErrorReported = true; + }; + + ClassTemplateDecl *TD = Class->getDescribedClassTemplate(); + if (!TD) { + auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(Class); + if (!SD) { + S.Diag(Class->getLocation(), + diag::err_cuda_device_builtin_surftex_ref_decl) + << /*surface*/ 0 << Class; + S.Diag(Class->getLocation(), + diag::note_cuda_device_builtin_surftex_should_be_template_class) + << Class; + return; + } + TD = SD->getSpecializedTemplate(); + } + + TemplateParameterList *Params = TD->getTemplateParameters(); + unsigned N = Params->size(); + + if (N != 2) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_n_args) + << TD << 2; + } + if (N > 0 && !isa<TemplateTypeParmDecl>(Params->getParam(0))) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*1st*/ 0 << /*type*/ 0; + } + if (N > 1) { + auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*2nd*/ 1 << /*integer*/ 1; + } + } +} + +static void checkCUDADeviceBuiltinTextureClassTemplate(Sema &S, + CXXRecordDecl *Class) { + bool ErrorReported = false; + auto reportIllegalClassTemplate = [&ErrorReported](Sema &S, + ClassTemplateDecl *TD) { + if (ErrorReported) + return; + S.Diag(TD->getLocation(), + diag::err_cuda_device_builtin_surftex_cls_template) + << /*texture*/ 1 << TD; + ErrorReported = true; + }; + + ClassTemplateDecl *TD = Class->getDescribedClassTemplate(); + if (!TD) { + auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(Class); + if (!SD) { + S.Diag(Class->getLocation(), + diag::err_cuda_device_builtin_surftex_ref_decl) + << /*texture*/ 1 << Class; + S.Diag(Class->getLocation(), + diag::note_cuda_device_builtin_surftex_should_be_template_class) + << Class; + return; + } + TD = SD->getSpecializedTemplate(); + } + + TemplateParameterList *Params = TD->getTemplateParameters(); + unsigned N = Params->size(); + + if (N != 3) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_n_args) + << TD << 3; + } + if (N > 0 && !isa<TemplateTypeParmDecl>(Params->getParam(0))) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*1st*/ 0 << /*type*/ 0; + } + if (N > 1) { + auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*2nd*/ 1 << /*integer*/ 1; + } + } + if (N > 2) { + auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(2)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*3rd*/ 2 << /*integer*/ 1; + } + } +} + void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) { // Mark any compiler-generated routines with the implicit code_seg attribute. for (auto *Method : Class->methods()) { @@ -5892,7 +6180,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); // MSVC inherits DLL attributes to partial class template specializations. - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && !ClassAttr) { + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr) { if (auto *Spec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Class)) { if (Attr *TemplateAttr = getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) { @@ -5912,7 +6200,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { return; } - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr->isInherited()) { // Diagnose dll attributes on members of class with dll attribute. for (Decl *Member : Class->decls()) { @@ -5977,8 +6265,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (MD->isInlined()) { // MinGW does not import or export inline methods. But do it for // template instantiations. - if (!Context.getTargetInfo().getCXXABI().isMicrosoft() && - !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() && + if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() && TSK != TSK_ExplicitInstantiationDeclaration && TSK != TSK_ExplicitInstantiationDefinition) continue; @@ -6151,7 +6438,7 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { case OO_Spaceship: // No point allowing this if <=> doesn't exist in the current language mode. - if (!getLangOpts().CPlusPlus2a) + if (!getLangOpts().CPlusPlus20) break; return DefaultedComparisonKind::ThreeWay; @@ -6160,7 +6447,7 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { case OO_Greater: case OO_GreaterEqual: // No point allowing this if <=> doesn't exist in the current language mode. - if (!getLangOpts().CPlusPlus2a) + if (!getLangOpts().CPlusPlus20) break; return DefaultedComparisonKind::Relational; @@ -6172,27 +6459,31 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { return DefaultedFunctionKind(); } -static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, - SourceLocation DefaultLoc) { - switch (S.getSpecialMember(MD)) { +static void DefineDefaultedFunction(Sema &S, FunctionDecl *FD, + SourceLocation DefaultLoc) { + Sema::DefaultedFunctionKind DFK = S.getDefaultedFunctionKind(FD); + if (DFK.isComparison()) + return S.DefineDefaultedComparison(DefaultLoc, FD, DFK.asComparison()); + + switch (DFK.asSpecialMember()) { case Sema::CXXDefaultConstructor: S.DefineImplicitDefaultConstructor(DefaultLoc, - cast<CXXConstructorDecl>(MD)); + cast<CXXConstructorDecl>(FD)); break; case Sema::CXXCopyConstructor: - S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); + S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD)); break; case Sema::CXXCopyAssignment: - S.DefineImplicitCopyAssignment(DefaultLoc, MD); + S.DefineImplicitCopyAssignment(DefaultLoc, cast<CXXMethodDecl>(FD)); break; case Sema::CXXDestructor: - S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD)); + S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(FD)); break; case Sema::CXXMoveConstructor: - S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); + S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD)); break; case Sema::CXXMoveAssignment: - S.DefineImplicitMoveAssignment(DefaultLoc, MD); + S.DefineImplicitMoveAssignment(DefaultLoc, cast<CXXMethodDecl>(FD)); break; case Sema::CXXInvalid: llvm_unreachable("Invalid special member."); @@ -6313,6 +6604,27 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, return HasNonDeletedCopyOrMove; } +/// Report an error regarding overriding, along with any relevant +/// overridden methods. +/// +/// \param DiagID the primary error to report. +/// \param MD the overriding method. +static bool +ReportOverrides(Sema &S, unsigned DiagID, const CXXMethodDecl *MD, + llvm::function_ref<bool(const CXXMethodDecl *)> Report) { + bool IssuedDiagnostic = false; + for (const CXXMethodDecl *O : MD->overridden_methods()) { + if (Report(O)) { + if (!IssuedDiagnostic) { + S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + IssuedDiagnostic = true; + } + S.Diag(O->getLocation(), diag::note_overridden_virtual_function); + } + } + return IssuedDiagnostic; +} + /// Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -6427,21 +6739,64 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // primary comparison functions (==, <=>). llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons; - auto CheckForDefaultedFunction = [&](FunctionDecl *FD) { - if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted()) + // Perform checks that can't be done until we know all the properties of a + // member function (whether it's defaulted, deleted, virtual, overriding, + // ...). + auto CheckCompletedMemberFunction = [&](CXXMethodDecl *MD) { + // A static function cannot override anything. + if (MD->getStorageClass() == SC_Static) { + if (ReportOverrides(*this, diag::err_static_overrides_virtual, MD, + [](const CXXMethodDecl *) { return true; })) + return; + } + + // A deleted function cannot override a non-deleted function and vice + // versa. + if (ReportOverrides(*this, + MD->isDeleted() ? diag::err_deleted_override + : diag::err_non_deleted_override, + MD, [&](const CXXMethodDecl *V) { + return MD->isDeleted() != V->isDeleted(); + })) { + if (MD->isDefaulted() && MD->isDeleted()) + // Explain why this defaulted function was deleted. + DiagnoseDeletedDefaultedFunction(MD); + return; + } + + // A consteval function cannot override a non-consteval function and vice + // versa. + if (ReportOverrides(*this, + MD->isConsteval() ? diag::err_consteval_override + : diag::err_non_consteval_override, + MD, [&](const CXXMethodDecl *V) { + return MD->isConsteval() != V->isConsteval(); + })) { + if (MD->isDefaulted() && MD->isDeleted()) + // Explain why this defaulted function was deleted. + DiagnoseDeletedDefaultedFunction(MD); return; + } + }; + + auto CheckForDefaultedFunction = [&](FunctionDecl *FD) -> bool { + if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted()) + return false; DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD); if (DFK.asComparison() == DefaultedComparisonKind::NotEqual || - DFK.asComparison() == DefaultedComparisonKind::Relational) + DFK.asComparison() == DefaultedComparisonKind::Relational) { DefaultedSecondaryComparisons.push_back(FD); - else - CheckExplicitlyDefaultedFunction(S, FD); + return true; + } + + CheckExplicitlyDefaultedFunction(S, FD); + return false; }; auto CompleteMemberFunction = [&](CXXMethodDecl *M) { // Check whether the explicitly-defaulted members are valid. - CheckForDefaultedFunction(M); + bool Incomplete = CheckForDefaultedFunction(M); // Skip the rest of the checks for a member of a dependent class. if (Record->isDependentType()) @@ -6488,7 +6843,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // 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()) - DefineImplicitSpecialMember(*this, M, M->getLocation()); + DefineDefaultedFunction(*this, M, M->getLocation()); + + if (!Incomplete) + CheckCompletedMemberFunction(M); }; // Check the destructor before any other member function. We need to @@ -6524,19 +6882,21 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { } } - if (HasMethodWithOverrideControl && - HasOverridingMethodWithoutOverrideControl) { - // At least one method has the 'override' control declared. - // Diagnose all other overridden methods which do not have 'override' - // specified on them. + if (HasOverridingMethodWithoutOverrideControl) { + bool HasInconsistentOverrideControl = HasMethodWithOverrideControl; for (auto *M : Record->methods()) - DiagnoseAbsenceOfOverrideControl(M); + DiagnoseAbsenceOfOverrideControl(M, HasInconsistentOverrideControl); } // Check the defaulted secondary comparisons after any other member functions. - for (FunctionDecl *FD : DefaultedSecondaryComparisons) + for (FunctionDecl *FD : DefaultedSecondaryComparisons) { CheckExplicitlyDefaultedFunction(S, FD); + // If this is a member function, we deferred checking it until now. + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) + CheckCompletedMemberFunction(MD); + } + // ms_struct is a request to use the same ABI rules as MSVC. Check // whether this class uses any C++ features that are implemented // completely differently in MSVC, and if so, emit a diagnostic. @@ -6546,7 +6906,11 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // headers, sweeping up a bunch of types that the project doesn't // really rely on MSVC-compatible layout for. We must therefore // support "ms_struct except for C++ stuff" as a secondary ABI. - if (Record->isMsStruct(Context) && + // Don't emit this diagnostic if the feature was enabled as a + // language option (as opposed to via a pragma or attribute), as + // the option -mms-bitfields otherwise essentially makes it impossible + // to build C++ code, unless this diagnostic is turned off. + if (Record->isMsStruct(Context) && !Context.getLangOpts().MSBitfields && (Record->isPolymorphic() || Record->getNumBases())) { Diag(Record->getLocation(), diag::warn_cxx_ms_struct); } @@ -6581,6 +6945,13 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // is especially required for cases like vtable assumption loads. MarkVTableUsed(Record->getInnerLocStart(), Record); } + + if (getLangOpts().CUDA) { + if (Record->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>()) + checkCUDADeviceBuiltinSurfaceClassTemplate(*this, Record); + else if (Record->hasAttr<CUDADeviceBuiltinTextureTypeAttr>()) + checkCUDADeviceBuiltinTextureClassTemplate(*this, Record); + } } /// Look up the special member function that would be called by a special @@ -6629,7 +7000,7 @@ public: : S(S), UseLoc(UseLoc) { bool DiagnosedMultipleConstructedBases = false; CXXRecordDecl *ConstructedBase = nullptr; - UsingDecl *ConstructedBaseUsing = nullptr; + BaseUsingDecl *ConstructedBaseIntroducer = nullptr; // Find the set of such base class subobjects and check that there's a // unique constructed subobject. @@ -6653,18 +7024,18 @@ public: // of type B, the program is ill-formed. if (!ConstructedBase) { ConstructedBase = DConstructedBase; - ConstructedBaseUsing = D->getUsingDecl(); + ConstructedBaseIntroducer = D->getIntroducer(); } else if (ConstructedBase != DConstructedBase && !Shadow->isInvalidDecl()) { if (!DiagnosedMultipleConstructedBases) { S.Diag(UseLoc, diag::err_ambiguous_inherited_constructor) << Shadow->getTargetDecl(); - S.Diag(ConstructedBaseUsing->getLocation(), - diag::note_ambiguous_inherited_constructor_using) + S.Diag(ConstructedBaseIntroducer->getLocation(), + diag::note_ambiguous_inherited_constructor_using) << ConstructedBase; DiagnosedMultipleConstructedBases = true; } - S.Diag(D->getUsingDecl()->getLocation(), + S.Diag(D->getIntroducer()->getLocation(), diag::note_ambiguous_inherited_constructor_using) << DConstructedBase; } @@ -6921,6 +7292,9 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) { return; } + if (DefKind.isComparison()) + UnusedPrivateFields.clear(); + if (DefKind.isSpecialMember() ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD), DefKind.asSpecialMember()) @@ -6955,7 +7329,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // C++2a changes the second bullet to instead delete the function if it's // defaulted on its first declaration, unless it's "an assignment operator, // and its return type differs or its parameter type is not a reference". - bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus2a && First; + bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus20 && First; bool ShouldDeleteForTypeMismatch = false; unsigned ExpectedParams = 1; if (CSM == CXXDefaultConstructor || CSM == CXXDestructor) @@ -7065,7 +7439,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // FIXME: This should not apply if the member is deleted. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); - if ((getLangOpts().CPlusPlus2a || + if ((getLangOpts().CPlusPlus20 || (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) : isa<CXXConstructorDecl>(MD))) && MD->isConstexpr() && !Constexpr && @@ -7083,7 +7457,10 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // If a function is explicitly defaulted on its first declaration, it is // implicitly considered to be constexpr if the implicit declaration // would be. - MD->setConstexprKind(Constexpr ? CSK_constexpr : CSK_unspecified); + MD->setConstexprKind(Constexpr ? (MD->isConsteval() + ? ConstexprSpecKind::Consteval + : ConstexprSpecKind::Constexpr) + : ConstexprSpecKind::Unspecified); if (!Type->hasExceptionSpec()) { // C++2a [except.spec]p3: @@ -7322,7 +7699,7 @@ public: private: Subobject getCompleteObject() { - return Subobject{Subobject::CompleteObject, nullptr, FD->getLocation()}; + return Subobject{Subobject::CompleteObject, RD, FD->getLocation()}; } Subobject getBase(CXXBaseSpecifier *Base) { @@ -7375,12 +7752,11 @@ private: if (Args[0]->getType()->isOverloadableType()) S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); - else { + else // FIXME: We determine whether this is a valid expression by checking to // see if there's a viable builtin operator candidate for it. That isn't // really what the rules ask us to do, but should give the right results. S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet); - } Result R; @@ -7424,11 +7800,14 @@ private: return Result::deleted(); } - // C++2a [class.compare.default]p3 [P2002R0]: - // A defaulted comparison function is constexpr-compatible if [...] - // no overlod resolution performed [...] results in a non-constexpr - // function. + bool NeedsDeducing = + OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType(); + if (FunctionDecl *BestFD = Best->Function) { + // C++2a [class.compare.default]p3 [P2002R0]: + // A defaulted comparison function is constexpr-compatible if + // [...] no overlod resolution performed [...] results in a + // non-constexpr function. assert(!BestFD->isDeleted() && "wrong overload resolution result"); // If it's not constexpr, explain why not. if (Diagnose == ExplainConstexpr && !BestFD->isConstexpr()) { @@ -7441,10 +7820,8 @@ private: return Result::deleted(); } R.Constexpr &= BestFD->isConstexpr(); - } - if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) { - if (auto *BestFD = Best->Function) { + if (NeedsDeducing) { // If any callee has an undeduced return type, deduce it now. // FIXME: It's not clear how a failure here should be handled. For // now, we produce an eager diagnostic, because that is forward @@ -7470,10 +7847,9 @@ private: } return Result::deleted(); } - if (auto *Info = S.Context.CompCategories.lookupInfoForType( - BestFD->getCallResultType())) { - R.Category = Info->Kind; - } else { + auto *Info = S.Context.CompCategories.lookupInfoForType( + BestFD->getCallResultType()); + if (!Info) { if (Diagnose == ExplainDeleted) { S.Diag(Subobj.Loc, diag::note_defaulted_comparison_cannot_deduce) << Subobj.Kind << Subobj.Decl @@ -7484,9 +7860,18 @@ private: } return Result::deleted(); } - } else { + R.Category = Info->Kind; + } + } else { + QualType T = Best->BuiltinParamTypes[0]; + assert(T == Best->BuiltinParamTypes[1] && + "builtin comparison for different types?"); + assert(Best->BuiltinParamTypes[2].isNull() && + "invalid builtin comparison"); + + if (NeedsDeducing) { Optional<ComparisonCategoryType> Cat = - getComparisonCategoryForBuiltinCmp(Args[0]->getType()); + getComparisonCategoryForBuiltinCmp(T); assert(Cat && "no category for builtin comparison?"); R.Category = *Cat; } @@ -7772,10 +8157,10 @@ private: if (ReturnFalse.isInvalid()) return StmtError(); - return S.ActOnIfStmt(Loc, false, nullptr, + return S.ActOnIfStmt(Loc, false, Loc, nullptr, S.ActOnCondition(nullptr, Loc, NotCond.get(), Sema::ConditionKind::Boolean), - ReturnFalse.get(), SourceLocation(), nullptr); + Loc, ReturnFalse.get(), SourceLocation(), nullptr); } StmtResult visitSubobjectArray(QualType Type, llvm::APInt Size, @@ -7927,9 +8312,9 @@ private: return StmtError(); // if (...) - return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, InitStmt, Cond, - ReturnStmt.get(), /*ElseLoc=*/SourceLocation(), - /*Else=*/nullptr); + return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, Loc, InitStmt, Cond, Loc, + ReturnStmt.get(), + /*ElseLoc=*/SourceLocation(), /*Else=*/nullptr); } case DefaultedComparisonKind::NotEqual: @@ -7947,7 +8332,7 @@ private: assert(!R->isUndeducedType() && "type should have been deduced already"); // Don't bother forming a no-op cast in the common case. - if (E->isRValue() && S.Context.hasSameType(E->getType(), R)) + if (E->isPRValue() && S.Context.hasSameType(E->getType(), R)) return E; return S.BuildCXXNamedCast(Loc, tok::kw_static_cast, S.Context.getTrivialTypeSourceInfo(R, Loc), E, @@ -7962,7 +8347,7 @@ static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S, UnresolvedSetImpl &Operators, OverloadedOperatorKind Op) { auto Lookup = [&](OverloadedOperatorKind OO) { - Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators); + Self.LookupOverloadedOperatorName(OO, S, Operators); }; // Every defaulted operator looks up itself. @@ -7986,9 +8371,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) { @@ -8006,43 +8388,17 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // const C&, 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 we're out-of-class, this is the class we're comparing. + if (!RD) + RD = MD->getParent(); + if (!MD->isConst()) { SourceLocation InsertLoc; if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc()) @@ -8051,7 +8407,7 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // corresponding defaulted 'operator<=>' already. if (!MD->isImplicit()) { Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const) - << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const"); + << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const"); } // Add the 'const' to the type to recover. @@ -8061,9 +8417,100 @@ 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 (FD->getNumParams() != (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()) { + QualType ParmTy = Param->getType(); + if (ParmTy->isDependentType()) + continue; + 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()); + if (IsMethod) + PlainTy = QualType(); + 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::find_if(RD->friends(), [&](const FriendDecl *F) { + return FD->getCanonicalDecl() == + F->getFriendDecl()->getCanonicalDecl(); + }) == RD->friends().end()) { + 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: @@ -8175,7 +8622,7 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // FIXME: Only applying this to the first declaration seems problematic, as // simple reorderings can affect the meaning of the program. if (First && !FD->isConstexpr() && Info.Constexpr) - FD->setConstexprKind(CSK_constexpr); + FD->setConstexprKind(ConstexprSpecKind::Constexpr); // C++2a [except.spec]p3: // If a declaration of a function does not have a noexcept-specifier @@ -8221,7 +8668,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 = @@ -9149,7 +9599,8 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, // brace-or-equal-initializer if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) { if (Diagnose) - S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << FI; + S.Diag(FI->getLocation(), diag::note_nontrivial_default_member_init) + << FI; return false; } @@ -9357,9 +9808,9 @@ public: bool foundSameNameMethod = false; SmallVector<CXXMethodDecl *, 8> overloadedMethods; - for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - NamedDecl *D = Path.Decls.front(); + for (Path.Decls = BaseRecord->lookup(Name).begin(); + Path.Decls != DeclContext::lookup_iterator(); ++Path.Decls) { + NamedDecl *D = *Path.Decls; if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { MD = MD->getCanonicalDecl(); foundSameNameMethod = true; @@ -9463,27 +9914,57 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) { } void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { - auto PrintDiagAndRemoveAttr = [&]() { + auto PrintDiagAndRemoveAttr = [&](unsigned N) { // No diagnostics if this is a template instantiation. - if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) + if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) { Diag(RD.getAttr<TrivialABIAttr>()->getLocation(), diag::ext_cannot_use_trivial_abi) << &RD; + Diag(RD.getAttr<TrivialABIAttr>()->getLocation(), + diag::note_cannot_use_trivial_abi_reason) << &RD << N; + } RD.dropAttr<TrivialABIAttr>(); }; + // Ill-formed if the copy and move constructors are deleted. + auto HasNonDeletedCopyOrMoveConstructor = [&]() { + // If the type is dependent, then assume it might have + // implicit copy or move ctor because we won't know yet at this point. + if (RD.isDependentType()) + return true; + if (RD.needsImplicitCopyConstructor() && + !RD.defaultedCopyConstructorIsDeleted()) + return true; + if (RD.needsImplicitMoveConstructor() && + !RD.defaultedMoveConstructorIsDeleted()) + return true; + for (const CXXConstructorDecl *CD : RD.ctors()) + if (CD->isCopyOrMoveConstructor() && !CD->isDeleted()) + return true; + return false; + }; + + if (!HasNonDeletedCopyOrMoveConstructor()) { + PrintDiagAndRemoveAttr(0); + return; + } + // Ill-formed if the struct has virtual functions. if (RD.isPolymorphic()) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(1); return; } for (const auto &B : RD.bases()) { // Ill-formed if the base class is non-trivial for the purpose of calls or a // virtual base. - if ((!B.getType()->isDependentType() && - !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) || - B.isVirtual()) { - PrintDiagAndRemoveAttr(); + if (!B.getType()->isDependentType() && + !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) { + PrintDiagAndRemoveAttr(2); + return; + } + + if (B.isVirtual()) { + PrintDiagAndRemoveAttr(3); return; } } @@ -9493,14 +9974,14 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { // non-trivial for the purpose of calls. QualType FT = FD->getType(); if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(4); return; } if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>()) if (!RT->isDependentType() && !cast<CXXRecordDecl>(RT->getDecl())->canPassInRegisters()) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(5); return; } } @@ -9573,86 +10054,95 @@ static void findImplicitlyDeclaredEqualityComparisons( /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { - if (ClassDecl->needsImplicitDefaultConstructor()) { - ++getASTContext().NumImplicitDefaultConstructors; + // Don't add implicit special members to templated classes. + // FIXME: This means unqualified lookups for 'operator=' within a class + // template don't work properly. + if (!ClassDecl->isDependentType()) { + if (ClassDecl->needsImplicitDefaultConstructor()) { + ++getASTContext().NumImplicitDefaultConstructors; - if (ClassDecl->hasInheritedConstructor()) - DeclareImplicitDefaultConstructor(ClassDecl); - } + if (ClassDecl->hasInheritedConstructor()) + DeclareImplicitDefaultConstructor(ClassDecl); + } - if (ClassDecl->needsImplicitCopyConstructor()) { - ++getASTContext().NumImplicitCopyConstructors; + if (ClassDecl->needsImplicitCopyConstructor()) { + ++getASTContext().NumImplicitCopyConstructors; - // If the properties or semantics of the copy constructor couldn't be - // determined while the class was being declared, force a declaration - // of it now. - if (ClassDecl->needsOverloadResolutionForCopyConstructor() || - ClassDecl->hasInheritedConstructor()) - DeclareImplicitCopyConstructor(ClassDecl); - // For the MS ABI we need to know whether the copy ctor is deleted. A - // prerequisite for deleting the implicit copy ctor is that the class has a - // move ctor or move assignment that is either user-declared or whose - // semantics are inherited from a subobject. FIXME: We should provide a more - // direct way for CodeGen to ask whether the constructor was deleted. - else if (Context.getTargetInfo().getCXXABI().isMicrosoft() && - (ClassDecl->hasUserDeclaredMoveConstructor() || - ClassDecl->needsOverloadResolutionForMoveConstructor() || - ClassDecl->hasUserDeclaredMoveAssignment() || - ClassDecl->needsOverloadResolutionForMoveAssignment())) - DeclareImplicitCopyConstructor(ClassDecl); - } + // If the properties or semantics of the copy constructor couldn't be + // determined while the class was being declared, force a declaration + // of it now. + if (ClassDecl->needsOverloadResolutionForCopyConstructor() || + ClassDecl->hasInheritedConstructor()) + DeclareImplicitCopyConstructor(ClassDecl); + // For the MS ABI we need to know whether the copy ctor is deleted. A + // prerequisite for deleting the implicit copy ctor is that the class has + // a move ctor or move assignment that is either user-declared or whose + // semantics are inherited from a subobject. FIXME: We should provide a + // more direct way for CodeGen to ask whether the constructor was deleted. + else if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + (ClassDecl->hasUserDeclaredMoveConstructor() || + ClassDecl->needsOverloadResolutionForMoveConstructor() || + ClassDecl->hasUserDeclaredMoveAssignment() || + ClassDecl->needsOverloadResolutionForMoveAssignment())) + DeclareImplicitCopyConstructor(ClassDecl); + } - if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) { - ++getASTContext().NumImplicitMoveConstructors; + if (getLangOpts().CPlusPlus11 && + ClassDecl->needsImplicitMoveConstructor()) { + ++getASTContext().NumImplicitMoveConstructors; - if (ClassDecl->needsOverloadResolutionForMoveConstructor() || - ClassDecl->hasInheritedConstructor()) - DeclareImplicitMoveConstructor(ClassDecl); - } + if (ClassDecl->needsOverloadResolutionForMoveConstructor() || + ClassDecl->hasInheritedConstructor()) + DeclareImplicitMoveConstructor(ClassDecl); + } - if (ClassDecl->needsImplicitCopyAssignment()) { - ++getASTContext().NumImplicitCopyAssignmentOperators; + if (ClassDecl->needsImplicitCopyAssignment()) { + ++getASTContext().NumImplicitCopyAssignmentOperators; - // If we have a dynamic class, then the copy assignment operator may be - // virtual, so we have to declare it immediately. This ensures that, e.g., - // it shows up in the right place in the vtable and that we diagnose - // problems with the implicit exception specification. - if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForCopyAssignment() || - ClassDecl->hasInheritedAssignment()) - DeclareImplicitCopyAssignment(ClassDecl); - } + // If we have a dynamic class, then the copy assignment operator may be + // virtual, so we have to declare it immediately. This ensures that, e.g., + // it shows up in the right place in the vtable and that we diagnose + // problems with the implicit exception specification. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForCopyAssignment() || + ClassDecl->hasInheritedAssignment()) + DeclareImplicitCopyAssignment(ClassDecl); + } - if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) { - ++getASTContext().NumImplicitMoveAssignmentOperators; + if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) { + ++getASTContext().NumImplicitMoveAssignmentOperators; - // Likewise for the move assignment operator. - if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForMoveAssignment() || - ClassDecl->hasInheritedAssignment()) - DeclareImplicitMoveAssignment(ClassDecl); - } + // Likewise for the move assignment operator. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForMoveAssignment() || + ClassDecl->hasInheritedAssignment()) + DeclareImplicitMoveAssignment(ClassDecl); + } - if (ClassDecl->needsImplicitDestructor()) { - ++getASTContext().NumImplicitDestructors; + if (ClassDecl->needsImplicitDestructor()) { + ++getASTContext().NumImplicitDestructors; - // If we have a dynamic class, then the destructor may be virtual, so we - // have to declare the destructor immediately. This ensures that, e.g., it - // shows up in the right place in the vtable and that we diagnose problems - // with the implicit exception specification. - if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForDestructor()) - DeclareImplicitDestructor(ClassDecl); + // If we have a dynamic class, then the destructor may be virtual, so we + // have to declare the destructor immediately. This ensures that, e.g., it + // shows up in the right place in the vtable and that we diagnose problems + // with the implicit exception specification. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForDestructor()) + DeclareImplicitDestructor(ClassDecl); + } } // C++2a [class.compare.default]p3: // If the member-specification does not explicitly declare any member or // friend named operator==, an == operator function is declared implicitly - // for each defaulted three-way comparison operator function defined in the - // member-specification + // for each defaulted three-way comparison operator function defined in + // the member-specification // FIXME: Consider doing this lazily. - if (getLangOpts().CPlusPlus2a) { - llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships; + // We do this during the initial parse for a class template, not during + // instantiation, so that we can handle unqualified lookups for 'operator==' + // when parsing the template. + if (getLangOpts().CPlusPlus20 && !inTemplateInstantiation()) { + llvm::SmallVector<FunctionDecl *, 4> DefaultedSpaceships; findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl, DefaultedSpaceships); for (auto *FD : DefaultedSpaceships) @@ -9660,19 +10150,17 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } -unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { +unsigned +Sema::ActOnReenterTemplateScope(Decl *D, + llvm::function_ref<Scope *()> EnterScope) { if (!D) return 0; + AdjustDeclIfTemplate(D); - // The order of template parameters is not important here. All names - // get added to the same scope. + // In order to get name lookup right, reenter template scopes in order from + // outermost to innermost. SmallVector<TemplateParameterList *, 4> ParameterLists; - - if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) - D = TD->getTemplatedDecl(); - - if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) - ParameterLists.push_back(PSD->getTemplateParameters()); + DeclContext *LookupDC = dyn_cast<DeclContext>(D); if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { for (unsigned i = 0; i < DD->getNumTemplateParameterLists(); ++i) @@ -9681,31 +10169,49 @@ unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) ParameterLists.push_back(FTD->getTemplateParameters()); - } - } + } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + LookupDC = VD->getDeclContext(); - if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) + ParameterLists.push_back(VTD->getTemplateParameters()); + else if (auto *PSD = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); + } + } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { for (unsigned i = 0; i < TD->getNumTemplateParameterLists(); ++i) ParameterLists.push_back(TD->getTemplateParameterList(i)); if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) { if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) ParameterLists.push_back(CTD->getTemplateParameters()); + else if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); } } + // FIXME: Alias declarations and concepts. unsigned Count = 0; + Scope *InnermostTemplateScope = nullptr; for (TemplateParameterList *Params : ParameterLists) { - if (Params->size() > 0) - // Ignore explicit specializations; they don't contribute to the template - // depth. - ++Count; + // Ignore explicit specializations; they don't contribute to the template + // depth. + if (Params->size() == 0) + continue; + + InnermostTemplateScope = EnterScope(); for (NamedDecl *Param : *Params) { if (Param->getDeclName()) { - S->AddDecl(Param); + InnermostTemplateScope->AddDecl(Param); IdResolver.AddDecl(Param); } } + ++Count; + } + + // Associate the new template scopes with the corresponding entities. + if (InnermostTemplateScope) { + assert(LookupDC && "no enclosing DeclContext for template lookup"); + EnterTemplatedContext(InnermostTemplateScope, LookupDC); } return Count; @@ -9757,11 +10263,6 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) { ParmVarDecl *Param = cast<ParmVarDecl>(ParamD); - // If this parameter has an unparsed default argument, clear it out - // to make way for the parsed default argument. - if (Param->hasUnparsedDefaultArg()) - Param->setDefaultArg(nullptr); - S->AddDecl(Param); if (Param->getDeclName()) IdResolver.AddDecl(Param); @@ -9895,11 +10396,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { // either there are no other parameters or else all other // parameters have default arguments. if (!Constructor->isInvalidDecl() && - ((Constructor->getNumParams() == 1) || - (Constructor->getNumParams() > 1 && - Constructor->getParamDecl(1)->hasDefaultArg())) && - Constructor->getTemplateSpecializationKind() - != TSK_ImplicitInstantiation) { + Constructor->hasOneParamOrDefaultArgs() && + Constructor->getTemplateSpecializationKind() != + TSK_ImplicitInstantiation) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { @@ -9984,12 +10483,12 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // declaration. QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name) << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); else if (const TemplateSpecializationType *TST = DeclaratorType->getAs<TemplateSpecializationType>()) if (TST->isTypeAlias()) - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name) << DeclaratorType << 1; // C++ [class.dtor]p2: @@ -10251,7 +10750,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. - if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a) + if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20) Diag(DS.getExplicitSpecLoc(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_explicit_conversion_functions @@ -10270,15 +10769,12 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { // Make sure we aren't redeclaring the conversion function. QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); - // C++ [class.conv.fct]p1: // [...] A conversion function is never used to convert a // (possibly cv-qualified) object to the (possibly cv-qualified) // same object type (or a reference to it), to a (possibly // cv-qualified) base class of that type (or a reference to it), // or to (possibly cv-qualified) void. - // FIXME: Suppress this warning if the conversion function ends up being a - // virtual function that overrides a virtual function in a base class. QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>()) @@ -10286,6 +10782,8 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { if (Conversion->getTemplateSpecializationKind() != TSK_Undeclared && Conversion->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) /* Suppress diagnostics for instantiations. */; + else if (Conversion->size_overridden_methods() != 0) + /* Suppress diagnostics for overriding virtual function in a base class. */; else if (ConvType->isRecordType()) { ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType(); if (ConvType == ClassType) @@ -10464,26 +10962,6 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, NamespaceDecl *PrevNS) { assert(*IsInline != PrevNS->isInline()); - // HACK: Work around a bug in libstdc++4.6's <atomic>, where - // std::__atomic[0,1,2] are defined as non-inline namespaces, then reopened as - // inline namespaces, with the intention of bringing names into namespace std. - // - // We support this just well enough to get that case working; this is not - // sufficient to support reopening namespaces as inline in general. - if (*IsInline && II && II->getName().startswith("__atomic") && - S.getSourceManager().isInSystemHeader(Loc)) { - // Mark all prior declarations of the namespace as inline. - for (NamespaceDecl *NS = PrevNS->getMostRecentDecl(); NS; - NS = NS->getPreviousDecl()) - NS->setInline(*IsInline); - // Patch up the lookup table for the containing namespace. This isn't really - // correct, but it's good enough for this particular case. - for (auto *I : PrevNS->decls()) - if (auto *ND = dyn_cast<NamedDecl>(I)) - PrevNS->getParent()->makeDeclVisibleInContext(ND); - return; - } - if (PrevNS->isInline()) // The user probably just forgot the 'inline', so suggest that it // be added back. @@ -10809,8 +11287,8 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, // Attempt to diagnose reasons why the STL definition of this type // might be foobar, including it failing to be a constant expression. // TODO Handle more ways the lookup or result can be invalid. - if (!VD->isStaticDataMember() || !VD->isConstexpr() || !VD->hasInit() || - !VD->checkInitIsICE()) + if (!VD->isStaticDataMember() || + !VD->isUsableInConstantExpressions(Context)) return UnsupportedSTLError(USS_InvalidMember, MemName, VD); // Attempt to evaluate the var decl as a constant expression and extract @@ -10960,8 +11438,7 @@ bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { // is of type std::initializer_list<E> or reference to possibly cv-qualified // std::initializer_list<E> for some type E, and either there are no other // parameters or else all other parameters have default arguments. - if (Ctor->getNumParams() < 1 || - (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg())) + if (!Ctor->hasOneParamOrDefaultArgs()) return false; QualType ArgType = Ctor->getParamDecl(0)->getType(); @@ -11202,7 +11679,41 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc, SS, TargetNameInfo, EllipsisLoc, AttrList, - /*IsInstantiation*/false); + /*IsInstantiation*/ false, + AttrList.hasAttribute(ParsedAttr::AT_UsingIfExists)); + if (UD) + PushOnScopeChains(UD, S, /*AddToContext*/ false); + + return UD; +} + +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 + return nullptr; + + case DeclSpec::TST_enum: + break; + + case DeclSpec::TST_typename: + Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent); + 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 (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); @@ -11222,13 +11733,19 @@ IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2) { return Context.hasSameType(TD1->getUnderlyingType(), TD2->getUnderlyingType()); + // Two using_if_exists using-declarations are equivalent if both are + // unresolved. + if (isa<UnresolvedUsingIfExistsDecl>(D1) && + isa<UnresolvedUsingIfExistsDecl>(D2)) + return true; + return false; } /// Determines whether to create a using shadow decl for a particular /// decl, given the set of decls existing prior to this using lookup. -bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, +bool Sema::CheckUsingShadowDecl(BaseUsingDecl *BUD, NamedDecl *Orig, const LookupResult &Previous, UsingShadowDecl *&PrevShadow) { // Diagnose finding a decl which is not from a base class of the @@ -11247,38 +11764,39 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // This is invalid (during instantiation) in C++03 because B::foo // resolves to the using decl in B, which is not a base class of D<T>. // We can't diagnose it immediately because C<T> is an unknown - // specialization. The UsingShadowDecl in D<T> then points directly + // specialization. The UsingShadowDecl in D<T> then points directly // to A::foo, which will look well-formed when we instantiate. // The right solution is to not collapse the shadow-decl chain. - if (!getLangOpts().CPlusPlus11 && CurContext->isRecord()) { - DeclContext *OrigDC = Orig->getDeclContext(); - - // Handle enums and anonymous structs. - if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent(); - CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC); - while (OrigRec->isAnonymousStructOrUnion()) - OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext()); - - if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { - if (OrigDC == CurContext) { - Diag(Using->getLocation(), - diag::err_using_decl_nested_name_specifier_is_current_class) - << Using->getQualifierLoc().getSourceRange(); + if (!getLangOpts().CPlusPlus11 && CurContext->isRecord()) + if (auto *Using = dyn_cast<UsingDecl>(BUD)) { + DeclContext *OrigDC = Orig->getDeclContext(); + + // Handle enums and anonymous structs. + if (isa<EnumDecl>(OrigDC)) + OrigDC = OrigDC->getParent(); + CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC); + while (OrigRec->isAnonymousStructOrUnion()) + OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext()); + + if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { + if (OrigDC == CurContext) { + Diag(Using->getLocation(), + diag::err_using_decl_nested_name_specifier_is_current_class) + << Using->getQualifierLoc().getSourceRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + Using->setInvalidDecl(); + return true; + } + + Diag(Using->getQualifierLoc().getBeginLoc(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << Using->getQualifier() << cast<CXXRecordDecl>(CurContext) + << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); Using->setInvalidDecl(); return true; } - - Diag(Using->getQualifierLoc().getBeginLoc(), - diag::err_using_decl_nested_name_specifier_is_not_base_class) - << Using->getQualifier() - << cast<CXXRecordDecl>(CurContext) - << Using->getQualifierLoc().getSourceRange(); - Diag(Orig->getLocation(), diag::note_using_decl_target); - Using->setInvalidDecl(); - return true; } - } if (Previous.empty()) return false; @@ -11299,7 +11817,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // We can have UsingDecls in our Previous results because we use the same // LookupResult for checking whether the UsingDecl itself is a valid // redeclaration. - if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D)) + if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D) || isa<UsingEnumDecl>(D)) continue; if (auto *RD = dyn_cast<CXXRecordDecl>(D)) { @@ -11311,7 +11829,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, !isa<UnresolvedUsingValueDecl>(Target) && DiagnoseClassNameShadow( CurContext, - DeclarationNameInfo(Using->getDeclName(), Using->getLocation()))) + DeclarationNameInfo(BUD->getDeclName(), BUD->getLocation()))) return true; } @@ -11332,6 +11850,20 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, if (FoundEquivalentDecl) return false; + // Always emit a diagnostic for a mismatch between an unresolved + // using_if_exists and a resolved using declaration in either direction. + if (isa<UnresolvedUsingIfExistsDecl>(Target) != + (isa_and_nonnull<UnresolvedUsingIfExistsDecl>(NonTag))) { + if (!NonTag && !Tag) + return false; + Diag(BUD->getLocation(), diag::err_using_decl_conflict); + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag((NonTag ? NonTag : Tag)->getLocation(), + diag::note_using_decl_conflict); + BUD->setInvalidDecl(); + return true; + } + if (FunctionDecl *FD = Target->getAsFunction()) { NamedDecl *OldDecl = nullptr; switch (CheckOverload(nullptr, FD, Previous, OldDecl, @@ -11340,7 +11872,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, return false; case Ovl_NonFunction: - Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(BUD->getLocation(), diag::err_using_decl_conflict); break; // We found a decl with the exact signature. @@ -11352,13 +11884,13 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, return true; // If we're not in a record, this is an error. - Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(BUD->getLocation(), diag::err_using_decl_conflict); break; } Diag(Target->getLocation(), diag::note_using_decl_target); Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); - Using->setInvalidDecl(); + BUD->setInvalidDecl(); return true; } @@ -11368,20 +11900,20 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // No conflict between a tag and a non-tag. if (!Tag) return false; - Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(BUD->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(Tag->getLocation(), diag::note_using_decl_conflict); - Using->setInvalidDecl(); + BUD->setInvalidDecl(); return true; } // No conflict between a tag and a non-tag. if (!NonTag) return false; - Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(BUD->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(NonTag->getLocation(), diag::note_using_decl_conflict); - Using->setInvalidDecl(); + BUD->setInvalidDecl(); return true; } @@ -11396,8 +11928,7 @@ static bool isVirtualDirectBase(CXXRecordDecl *Derived, CXXRecordDecl *Base) { } /// Builds a shadow declaration corresponding to a 'using' declaration. -UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, - UsingDecl *UD, +UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, BaseUsingDecl *BUD, NamedDecl *Orig, UsingShadowDecl *PrevDecl) { // If we resolved to another shadow declaration, just coalesce them. @@ -11413,19 +11944,20 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow; if (NonTemplateTarget && isa<CXXConstructorDecl>(NonTemplateTarget)) { + UsingDecl *Using = cast<UsingDecl>(BUD); bool IsVirtualBase = isVirtualDirectBase(cast<CXXRecordDecl>(CurContext), - UD->getQualifier()->getAsRecordDecl()); + Using->getQualifier()->getAsRecordDecl()); Shadow = ConstructorUsingShadowDecl::Create( - Context, CurContext, UD->getLocation(), UD, Orig, IsVirtualBase); + Context, CurContext, Using->getLocation(), Using, Orig, IsVirtualBase); } else { - Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD, - Target); + Shadow = UsingShadowDecl::Create(Context, CurContext, BUD->getLocation(), + Target->getDeclName(), BUD, Target); } - UD->addShadowDecl(Shadow); + BUD->addShadowDecl(Shadow); - Shadow->setAccess(UD->getAccess()); - if (Orig->isInvalidDecl() || UD->isInvalidDecl()) + Shadow->setAccess(BUD->getAccess()); + if (Orig->isInvalidDecl() || BUD->isInvalidDecl()) Shadow->setInvalidDecl(); Shadow->setPreviousDecl(PrevDecl); @@ -11481,7 +12013,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { } // ...and the using decl. - Shadow->getUsingDecl()->removeShadowDecl(Shadow); + Shadow->getIntroducer()->removeShadowDecl(Shadow); // TODO: complain somehow if Shadow was used. It shouldn't // be possible for this to happen, because...? @@ -11587,6 +12119,29 @@ private: }; } // end anonymous namespace +/// Remove decls we can't actually see from a lookup being used to declare +/// shadow using decls. +/// +/// \param S - The scope of the potential shadow decl +/// \param Previous - The lookup of a potential shadow decl's name. +void Sema::FilterUsingLookup(Scope *S, LookupResult &Previous) { + // It is really dumb that we have to do this. + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (!isDeclInScope(D, CurContext, S)) + F.erase(); + // If we found a local extern declaration that's not ordinarily visible, + // and this declaration is being added to a non-block scope, ignore it. + // We're only checking for scope conflicts here, not also for violations + // of the linkage rules. + else if (!CurContext->isFunctionOrMethod() && D->isLocalExternDecl() && + !(D->getIdentifierNamespace() & Decl::IDNS_Ordinary)) + F.erase(); + } + F.done(); +} + /// Builds a using declaration. /// /// \param IsInstantiation - Whether this call arises from an @@ -11596,7 +12151,8 @@ NamedDecl *Sema::BuildUsingDeclaration( Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, - const ParsedAttributesView &AttrList, bool IsInstantiation) { + const ParsedAttributesView &AttrList, bool IsInstantiation, + bool IsUsingIfExists) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); SourceLocation IdentLoc = NameInfo.getLoc(); assert(IdentLoc.isValid() && "Invalid TargetName location."); @@ -11619,21 +12175,7 @@ NamedDecl *Sema::BuildUsingDeclaration( if (S) { LookupName(Previous, S); - // It is really dumb that we have to do this. - LookupResult::Filter F = Previous.makeFilter(); - while (F.hasNext()) { - NamedDecl *D = F.next(); - if (!isDeclInScope(D, CurContext, S)) - F.erase(); - // If we found a local extern declaration that's not ordinarily visible, - // and this declaration is being added to a non-block scope, ignore it. - // We're only checking for scope conflicts here, not also for violations - // of the linkage rules. - else if (!CurContext->isFunctionOrMethod() && D->isLocalExternDecl() && - !(D->getIdentifierNamespace() & Decl::IDNS_Ordinary)) - F.erase(); - } - F.done(); + FilterUsingLookup(S, Previous); } else { assert(IsInstantiation && "no scope in non-instantiation"); if (CurContext->isRecord()) @@ -11660,15 +12202,22 @@ NamedDecl *Sema::BuildUsingDeclaration( SS, IdentLoc, Previous)) return nullptr; - // Check for bad qualifiers. - if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo, - IdentLoc)) + // 'using_if_exists' doesn't make sense on an inherited constructor. + if (IsUsingIfExists && UsingName.getName().getNameKind() == + DeclarationName::CXXConstructorName) { + Diag(UsingLoc, diag::err_using_if_exists_on_ctor); return nullptr; + } DeclContext *LookupContext = computeDeclContext(SS); - NamedDecl *D; NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); if (!LookupContext || EllipsisLoc.isValid()) { + NamedDecl *D; + // Dependent scope, or an unexpanded pack + if (!LookupContext && CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, + SS, NameInfo, IdentLoc)) + return nullptr; + if (HasTypenameKeyword) { // FIXME: not all declaration name kinds are legal here D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, @@ -11682,6 +12231,7 @@ NamedDecl *Sema::BuildUsingDeclaration( } D->setAccess(AS); CurContext->addDecl(D); + ProcessDeclAttributeList(S, D, AttrList); return D; } @@ -11691,6 +12241,7 @@ NamedDecl *Sema::BuildUsingDeclaration( UsingName, HasTypenameKeyword); UD->setAccess(AS); CurContext->addDecl(UD); + ProcessDeclAttributeList(S, UD, AttrList); UD->setInvalidDecl(Invalid); return UD; }; @@ -11719,16 +12270,25 @@ NamedDecl *Sema::BuildUsingDeclaration( LookupQualifiedName(R, LookupContext); + // Validate the context, now we have a lookup + if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo, + IdentLoc, &R)) + return nullptr; + + if (R.empty() && IsUsingIfExists) + R.addDecl(UnresolvedUsingIfExistsDecl::Create(Context, CurContext, UsingLoc, + UsingName.getName()), + AS_public); + // Try to correct typos if possible. If constructor name lookup finds no // results, that means the named class has no explicit constructors, and we // suppressed declaring implicit ones (probably because it's dependent or // invalid). if (R.empty() && NameInfo.getName().getNameKind() != DeclarationName::CXXConstructorName) { - // HACK: Work around a bug in libstdc++'s detection of ::gets. Sometimes - // it will believe that glibc provides a ::gets in cases where it does not, - // and will try to pull it into namespace std with a using-declaration. - // Just ignore the using-declaration in that case. + // HACK 2017-01-08: Work around an issue with libstdc++'s detection of + // ::gets. Sometimes it believes that glibc provides a ::gets in cases where + // it does not. The issue was fixed in libstdc++ 6.3 (2016-12-21) and later. auto *II = NameInfo.getName().getAsIdentifierInfo(); if (getLangOpts().CPlusPlus14 && II && II->isStr("gets") && CurContext->isStdNamespace() && @@ -11793,7 +12353,8 @@ NamedDecl *Sema::BuildUsingDeclaration( if (HasTypenameKeyword) { // If we asked for a typename and got a non-type decl, error out. - if (!R.getAsSingle<TypeDecl>()) { + if (!R.getAsSingle<TypeDecl>() && + !R.getAsSingle<UnresolvedUsingIfExistsDecl>()) { Diag(IdentLoc, diag::err_using_typename_non_type); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) Diag((*I)->getUnderlyingDecl()->getLocation(), @@ -11819,16 +12380,6 @@ NamedDecl *Sema::BuildUsingDeclaration( return BuildInvalid(); } - // C++14 [namespace.udecl]p7: - // A using-declaration shall not name a scoped enumerator. - if (auto *ED = R.getAsSingle<EnumConstantDecl>()) { - if (cast<EnumDecl>(ED->getDeclContext())->isScoped()) { - Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum) - << SS.getRange(); - return BuildInvalid(); - } - } - UsingDecl *UD = BuildValid(); // Some additional rules apply to inheriting constructors. @@ -11850,6 +12401,61 @@ NamedDecl *Sema::BuildUsingDeclaration( return UD; } +NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, + SourceLocation NameLoc, + EnumDecl *ED) { + bool Invalid = false; + + if (CurContext->getRedeclContext()->isRecord()) { + /// In class scope, check if this is a duplicate, for better a diagnostic. + DeclarationNameInfo UsingEnumName(ED->getDeclName(), NameLoc); + LookupResult Previous(*this, UsingEnumName, LookupUsingDeclName, + ForVisibleRedeclaration); + + LookupName(Previous, S); + + for (NamedDecl *D : Previous) + if (UsingEnumDecl *UED = dyn_cast<UsingEnumDecl>(D)) + if (UED->getEnumDecl() == ED) { + Diag(UsingLoc, diag::err_using_enum_decl_redeclaration) + << SourceRange(EnumLoc, NameLoc); + Diag(D->getLocation(), diag::note_using_enum_decl) << 1; + Invalid = true; + break; + } + } + + if (RequireCompleteEnumDecl(ED, NameLoc)) + Invalid = true; + + UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc, + EnumLoc, NameLoc, ED); + UD->setAccess(AS); + CurContext->addDecl(UD); + + if (Invalid) { + UD->setInvalidDecl(); + return UD; + } + + // Create the shadow decls for each enumerator + for (EnumConstantDecl *EC : ED->enumerators()) { + UsingShadowDecl *PrevDecl = nullptr; + DeclarationNameInfo DNI(EC->getDeclName(), EC->getLocation()); + LookupResult Previous(*this, DNI, LookupOrdinaryName, + ForVisibleRedeclaration); + LookupName(Previous, S); + FilterUsingLookup(S, Previous); + + if (!CheckUsingShadowDecl(UD, EC, Previous, PrevDecl)) + BuildUsingShadowDecl(S, UD, EC, PrevDecl); + } + + return UD; +} + NamedDecl *Sema::BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef<NamedDecl *> Expansions) { assert(isa<UnresolvedUsingValueDecl>(InstantiatedFrom) || @@ -11931,6 +12537,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, return false; } + const NestedNameSpecifier *CNNS = + Context.getCanonicalNestedNameSpecifier(Qual); for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; @@ -11956,8 +12564,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // using decls differ if they name different scopes (but note that // template instantiation can cause this check to trigger when it // didn't before instantiation). - if (Context.getCanonicalNestedNameSpecifier(Qual) != - Context.getCanonicalNestedNameSpecifier(DQual)) + if (CNNS != Context.getCanonicalNestedNameSpecifier(DQual)) continue; Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); @@ -11968,48 +12575,83 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, return false; } - /// Checks that the given nested-name qualifier used in a using decl /// in the current context is appropriately related to the current /// scope. If an error is found, diagnoses it and returns true. -bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, - bool HasTypename, +/// R is nullptr, if the caller has not (yet) done a lookup, otherwise it's the +/// result of that lookup. UD is likewise nullptr, except when we have an +/// already-populated UsingDecl whose shadow decls contain the same information +/// (i.e. we're instantiating a UsingDecl with non-dependent scope). +bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, - SourceLocation NameLoc) { + SourceLocation NameLoc, + const LookupResult *R, const UsingDecl *UD) { DeclContext *NamedContext = computeDeclContext(SS); + assert(bool(NamedContext) == (R || UD) && !(R && UD) && + "resolvable context must have exactly one set of decls"); + + // C++ 20 permits using an enumerator that does not have a class-hierarchy + // relationship. + bool Cxx20Enumerator = false; + if (NamedContext) { + EnumConstantDecl *EC = nullptr; + if (R) + EC = R->getAsSingle<EnumConstantDecl>(); + else if (UD && UD->shadow_size() == 1) + EC = dyn_cast<EnumConstantDecl>(UD->shadow_begin()->getTargetDecl()); + if (EC) + Cxx20Enumerator = getLangOpts().CPlusPlus20; + + if (auto *ED = dyn_cast<EnumDecl>(NamedContext)) { + // C++14 [namespace.udecl]p7: + // A using-declaration shall not name a scoped enumerator. + // C++20 p1099 permits enumerators. + if (EC && R && ED->isScoped()) + Diag(SS.getBeginLoc(), + getLangOpts().CPlusPlus20 + ? diag::warn_cxx17_compat_using_decl_scoped_enumerator + : diag::ext_using_decl_scoped_enumerator) + << SS.getRange(); + + // We want to consider the scope of the enumerator + NamedContext = ED->getDeclContext(); + } + } if (!CurContext->isRecord()) { // C++03 [namespace.udecl]p3: // C++0x [namespace.udecl]p8: // A using-declaration for a class member shall be a member-declaration. + // C++20 [namespace.udecl]p7 + // ... other than an enumerator ... // If we weren't able to compute a valid scope, it might validly be a - // dependent class scope or a dependent enumeration unscoped scope. If - // we have a 'typename' keyword, the scope must resolve to a class type. - if ((HasTypename && !NamedContext) || - (NamedContext && NamedContext->getRedeclContext()->isRecord())) { - auto *RD = NamedContext - ? cast<CXXRecordDecl>(NamedContext->getRedeclContext()) - : nullptr; - if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD)) - RD = nullptr; - - Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member) + // dependent class or enumeration scope. If we have a 'typename' keyword, + // the scope must resolve to a class type. + if (NamedContext ? !NamedContext->getRedeclContext()->isRecord() + : !HasTypename) + return false; // OK + + Diag(NameLoc, + Cxx20Enumerator + ? diag::warn_cxx17_compat_using_decl_class_member_enumerator + : diag::err_using_decl_can_not_refer_to_class_member) << SS.getRange(); - // If we have a complete, non-dependent source type, try to suggest a - // way to get the same effect. - if (!RD) - return true; + if (Cxx20Enumerator) + return false; // OK - // Find what this using-declaration was referring to. - LookupResult R(*this, NameInfo, LookupOrdinaryName); - R.setHideTags(false); - R.suppressDiagnostics(); - LookupQualifiedName(R, RD); + auto *RD = NamedContext + ? cast<CXXRecordDecl>(NamedContext->getRedeclContext()) + : nullptr; + if (RD && !RequireCompleteDeclContext(const_cast<CXXScopeSpec &>(SS), RD)) { + // See if there's a helpful fixit - if (R.getAsSingle<TypeDecl>()) { + if (!R) { + // We will have already diagnosed the problem on the template + // definition, Maybe we should do so again? + } else if (R->getAsSingle<TypeDecl>()) { if (getLangOpts().CPlusPlus11) { // Convert 'using X::Y;' to 'using Y = X::Y;'. Diag(SS.getBeginLoc(), diag::note_using_decl_class_member_workaround) @@ -12026,7 +12668,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, << FixItHint::CreateInsertion( InsertLoc, " " + NameInfo.getName().getAsString()); } - } else if (R.getAsSingle<VarDecl>()) { + } else if (R->getAsSingle<VarDecl>()) { // Don't provide a fixit outside C++11 mode; we don't want to suggest // repeating the type of the static data member here. FixItHint FixIt; @@ -12039,7 +12681,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, Diag(UsingLoc, diag::note_using_decl_class_member_workaround) << 2 // reference declaration << FixIt; - } else if (R.getAsSingle<EnumConstantDecl>()) { + } else if (R->getAsSingle<EnumConstantDecl>()) { // Don't provide a fixit outside C++11 mode; we don't want to suggest // repeating the type of the enumeration here, and we can't do so if // the type is anonymous. @@ -12055,15 +12697,11 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, << (getLangOpts().CPlusPlus11 ? 4 : 3) // const[expr] variable << FixIt; } - return true; } - // Otherwise, this might be valid. - return false; + return true; // Fail } - // The current scope is a record. - // If the named context is dependent, we can't decide much. if (!NamedContext) { // FIXME: in C++0x, we can diagnose if we can prove that the @@ -12075,12 +12713,19 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return false; } + // The current scope is a record. if (!NamedContext->isRecord()) { // Ideally this would point at the last name in the specifier, // but we don't have that level of source info. - Diag(SS.getRange().getBegin(), - diag::err_using_decl_nested_name_specifier_is_not_class) - << SS.getScopeRep() << SS.getRange(); + Diag(SS.getBeginLoc(), + Cxx20Enumerator + ? diag::warn_cxx17_compat_using_decl_non_member_enumerator + : diag::err_using_decl_nested_name_specifier_is_not_class) + << SS.getScopeRep() << SS.getRange(); + + if (Cxx20Enumerator) + return false; // OK + return true; } @@ -12096,19 +12741,25 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom( cast<CXXRecordDecl>(NamedContext))) { + + if (Cxx20Enumerator) { + Diag(NameLoc, diag::warn_cxx17_compat_using_decl_non_member_enumerator) + << SS.getRange(); + return false; + } + if (CurContext == NamedContext) { - Diag(NameLoc, + Diag(SS.getBeginLoc(), diag::err_using_decl_nested_name_specifier_is_current_class) - << SS.getRange(); - return true; + << SS.getRange(); + return !getLangOpts().CPlusPlus20; } if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) { - Diag(SS.getRange().getBegin(), + Diag(SS.getBeginLoc(), diag::err_using_decl_nested_name_specifier_is_not_base_class) - << SS.getScopeRep() - << cast<CXXRecordDecl>(CurContext) - << SS.getRange(); + << SS.getScopeRep() << cast<CXXRecordDecl>(CurContext) + << SS.getRange(); } return true; } @@ -12608,6 +13259,16 @@ void Sema::setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem, auto QT = Context.getFunctionType(ResultTy, Args, EPI); SpecialMem->setType(QT); + + // During template instantiation of implicit special member functions we need + // a reliable TypeSourceInfo for the function prototype in order to allow + // functions to be substituted. + if (inTemplateInstantiation() && + cast<CXXRecordDecl>(SpecialMem->getParent())->isLambda()) { + TypeSourceInfo *TSI = + Context.getTrivialTypeSourceInfo(SpecialMem->getType()); + SpecialMem->setTypeSourceInfo(TSI); + } } CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( @@ -12640,7 +13301,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); @@ -12761,7 +13423,7 @@ Sema::findInheritingConstructor(SourceLocation Loc, Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, BaseCtor->getExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified, + Constexpr ? BaseCtor->getConstexprKind() : ConstexprSpecKind::Unspecified, InheritedConstructor(Shadow, BaseCtor), BaseCtor->getTrailingRequiresClause()); if (Shadow->isInvalidDecl()) @@ -12918,7 +13580,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), nullptr, /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); Destructor->setAccess(AS_public); Destructor->setDefaulted(); @@ -13000,6 +13663,25 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } } +void Sema::CheckCompleteDestructorVariant(SourceLocation CurrentLocation, + CXXDestructorDecl *Destructor) { + if (Destructor->isInvalidDecl()) + return; + + CXXRecordDecl *ClassDecl = Destructor->getParent(); + assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && + "implicit complete dtors unneeded outside MS ABI"); + assert(ClassDecl->getNumVBases() > 0 && + "complete dtor only exists for classes with vbases"); + + SynthesizedFunctionScope Scope(*this, Destructor); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + MarkVirtualBaseDestructorsReferenced(Destructor->getLocation(), ClassDecl); +} + /// Perform any semantic analysis which needs to be delayed until all /// pending class member declarations have been parsed. void Sema::ActOnFinishCXXMemberDecls() { @@ -13021,7 +13703,7 @@ void Sema::ActOnFinishCXXNonNestedClass() { SmallVector<CXXMethodDecl*, 4> WorkList; std::swap(DelayedDllExportMemberFunctions, WorkList); for (CXXMethodDecl *M : WorkList) { - DefineImplicitSpecialMember(*this, M, M->getLocation()); + DefineDefaultedFunction(*this, M, M->getLocation()); // Pass the method to the consumer to get emitted. This is not necessary // for explicit instantiation definitions, as they will get emitted @@ -13220,13 +13902,13 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, // directly construct UnaryOperators here because semantic analysis // does not permit us to take the address of an xvalue. Expr *From = FromB.build(S, Loc); - From = new (S.Context) UnaryOperator(From, UO_AddrOf, - S.Context.getPointerType(From->getType()), - VK_RValue, OK_Ordinary, Loc, false); + From = UnaryOperator::Create( + S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()), + VK_PRValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); Expr *To = ToB.build(S, Loc); - To = new (S.Context) UnaryOperator(To, UO_AddrOf, - S.Context.getPointerType(To->getType()), - VK_RValue, OK_Ordinary, Loc, false); + To = UnaryOperator::Create( + S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()), + VK_PRValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = @@ -13248,7 +13930,7 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, return StmtError(); ExprResult MemCpyRef = S.BuildDeclRefExpr(MemCpy, S.Context.BuiltinFnTy, - VK_RValue, Loc, nullptr); + VK_PRValue, Loc, nullptr); assert(MemCpyRef.isUsable() && "Builtin reference cannot fail"); Expr *CallArgs[] = { @@ -13460,18 +14142,18 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, // Create the comparison against the array bound. llvm::APInt Upper = ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType)); - Expr *Comparison - = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc), - IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), - BO_NE, S.Context.BoolTy, - VK_RValue, OK_Ordinary, Loc, FPOptions()); + Expr *Comparison = BinaryOperator::Create( + S.Context, IterationVarRefRVal.build(S, Loc), + IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE, + S.Context.BoolTy, VK_PRValue, OK_Ordinary, Loc, + S.CurFPFeatureOverrides()); // Create the pre-increment of the iteration variable. We can determine // whether the increment will overflow based on the value of the array // bound. - Expr *Increment = new (S.Context) - UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType, - VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue()); + Expr *Increment = UnaryOperator::Create( + S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue, + OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatureOverrides()); // Construct the loop that copies all elements of this array. return S.ActOnForStmt( @@ -13535,7 +14217,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, - /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified, + /*isInline=*/true, + Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); @@ -13569,8 +14252,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyAssignment); - if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) + if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) { + ClassDecl->setImplicitCopyAssignmentIsDeleted(); SetDeclDeleted(CopyAssignment, ClassLoc); + } if (S) PushOnScopeChains(CopyAssignment, S, false); @@ -13616,12 +14301,20 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { assert(UserDeclaredOperation); } - if (UserDeclaredOperation && UserDeclaredOperation->isUserProvided()) { - S.Diag(UserDeclaredOperation->getLocation(), - isa<CXXDestructorDecl>(UserDeclaredOperation) - ? diag::warn_deprecated_copy_dtor_operation - : diag::warn_deprecated_copy_operation) - << RD << /*copy assignment*/ !isa<CXXConstructorDecl>(CopyOp); + if (UserDeclaredOperation) { + bool UDOIsUserProvided = UserDeclaredOperation->isUserProvided(); + bool UDOIsDestructor = isa<CXXDestructorDecl>(UserDeclaredOperation); + bool IsCopyAssignment = !isa<CXXConstructorDecl>(CopyOp); + unsigned DiagID = + (UDOIsUserProvided && UDOIsDestructor) + ? diag::warn_deprecated_copy_with_user_provided_dtor + : (UDOIsUserProvided && !UDOIsDestructor) + ? diag::warn_deprecated_copy_with_user_provided_copy + : (!UDOIsUserProvided && UDOIsDestructor) + ? diag::warn_deprecated_copy_with_dtor + : diag::warn_deprecated_copy; + S.Diag(UserDeclaredOperation->getLocation(), DiagID) + << RD << IsCopyAssignment; } } @@ -13858,7 +14551,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, - /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified, + /*isInline=*/true, + Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); MoveAssignment->setAccess(AS_public); MoveAssignment->setDefaulted(); @@ -13871,10 +14565,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { /* Diagnose */ false); } - // Build an exception specification pointing back at this member. - FunctionProtoType::ExtProtoInfo EPI = - getImplicitMethodEPI(*this, MoveAssignment); - MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI)); + setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, @@ -14242,7 +14933,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); @@ -14255,12 +14947,18 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( 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 + // to be substituted. + TypeSourceInfo *TSI = nullptr; + if (inTemplateInstantiation() && ClassDecl->isLambda()) + TSI = Context.getTrivialTypeSourceInfo(ArgType); + // Add the parameter to the constructor. - ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, - ClassLoc, ClassLoc, - /*IdentifierInfo=*/nullptr, - ArgType, /*TInfo=*/nullptr, - SC_None, nullptr); + ParmVarDecl *FromParam = + ParmVarDecl::Create(Context, CopyConstructor, ClassLoc, ClassLoc, + /*IdentifierInfo=*/nullptr, ArgType, + /*TInfo=*/TSI, SC_None, nullptr); CopyConstructor->setParams(FromParam); CopyConstructor->setTrivial( @@ -14375,7 +15073,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( ExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); @@ -14477,9 +15176,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( SynthesizedFunctionScope Scope(*this, Conv); assert(!Conv->getReturnType()->isUndeducedType()); + QualType ConvRT = Conv->getType()->castAs<FunctionType>()->getReturnType(); + CallingConv CC = + ConvRT->getPointeeType()->castAs<FunctionType>()->getCallConv(); + CXXRecordDecl *Lambda = Conv->getParent(); FunctionDecl *CallOp = Lambda->getLambdaCallOperator(); - FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(); + FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC); if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) { CallOp = InstantiateFunctionDeclaration( @@ -14550,9 +15253,9 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( // (since it's unusable otherwise); in the case where we inline the // block literal, it has block literal lifetime semantics. if (!BuildBlock.isInvalid() && !getLangOpts().ObjCAutoRefCount) - BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock.get()->getType(), - CK_CopyAndAutoreleaseBlockObject, - BuildBlock.get(), nullptr, VK_RValue); + BuildBlock = ImplicitCastExpr::Create( + Context, BuildBlock.get()->getType(), CK_CopyAndAutoreleaseBlockObject, + BuildBlock.get(), nullptr, VK_PRValue, FPOptionsOverride()); if (BuildBlock.isInvalid()) { Diag(CurrentLocation, diag::note_lambda_to_block_conv); @@ -14624,8 +15327,17 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_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. + // Right now it assumes the source object is passed directly as the + // first argument. Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { Expr *SubExpr = ExprArgs[0]; + // FIXME: Per above, this is also incorrect if we want to accept + // converting constructors, as isTemporaryObject will + // reject temporaries with different type from the + // CXXRecord itself. Elidable = SubExpr->isTemporaryObject( Context, cast<CXXRecordDecl>(FoundDecl->getDeclContext())); } @@ -14682,13 +15394,18 @@ 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 CXXConstructExpr::Create( - Context, DeclInitType, ConstructLoc, Constructor, Elidable, - ExprArgs, HadMultipleCandidates, IsListInitialization, - IsStdInitListInitialization, RequiresZeroInit, - static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), - ParenRange); + return CheckForImmediateInvocation( + CXXConstructExpr::Create( + Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs, + HadMultipleCandidates, IsListInitialization, + IsStdInitListInitialization, RequiresZeroInit, + static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), + ParenRange), + Constructor); } ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { @@ -14711,24 +15428,14 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - // Lookup can return at most two results: the pattern for the field, or the - // injected class name of the parent record. No other member can have the - // same name as the field. - // In modules mode, lookup can return multiple results (coming from - // different modules). - assert((getLangOpts().Modules || (!Lookup.empty() && Lookup.size() <= 2)) && - "more than two lookup results for field name"); - FieldDecl *Pattern = dyn_cast<FieldDecl>(Lookup[0]); - if (!Pattern) { - assert(isa<CXXRecordDecl>(Lookup[0]) && - "cannot have other non-field member with same name"); - for (auto L : Lookup) - if (isa<FieldDecl>(L)) { - Pattern = cast<FieldDecl>(L); - break; - } - assert(Pattern && "We must have set the Pattern!"); + 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, @@ -14755,9 +15462,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { // 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_in_class_initializer_not_yet_parsed) + Diag(Loc, diag::err_default_member_initializer_not_yet_parsed) << OutermostClass << Field; - Diag(Field->getEndLoc(), diag::note_in_class_initializer_not_yet_parsed); + 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(); @@ -14766,6 +15474,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { 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. + if (VD->getInit() && VD->getInit()->containsErrors()) + return; CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); if (ClassDecl->isInvalidDecl()) return; @@ -14792,10 +15504,13 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { // If the destructor is constexpr, check whether the variable has constant // destruction now. - if (Destructor->isConstexpr() && VD->getInit() && - !VD->getInit()->isValueDependent() && VD->evaluateValue()) { + if (Destructor->isConstexpr()) { + bool HasConstantInit = false; + if (VD->getInit() && !VD->getInit()->isValueDependent()) + HasConstantInit = VD->evaluateValue(); SmallVector<PartialDiagnosticAt, 8> Notes; - if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) { + if (!VD->evaluateDestruction(Notes) && VD->isConstexpr() && + HasConstantInit) { Diag(VD->getLocation(), diag::err_constexpr_var_requires_const_destruction) << VD; for (unsigned I = 0, N = Notes.size(); I != N; ++I) @@ -14819,13 +15534,12 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { /// to form a proper call to this constructor. /// /// \returns true if an error occurred, false otherwise. -bool -Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, - MultiExprArg ArgsPtr, - SourceLocation Loc, - SmallVectorImpl<Expr*> &ConvertedArgs, - bool AllowExplicit, - bool IsListInitialization) { +bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, + QualType DeclInitType, MultiExprArg ArgsPtr, + SourceLocation Loc, + SmallVectorImpl<Expr *> &ConvertedArgs, + bool AllowExplicit, + bool IsListInitialization) { // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. unsigned NumArgs = ArgsPtr.size(); Expr **Args = ArgsPtr.data(); @@ -14852,7 +15566,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, DiagnoseSentinelCalls(Constructor, Loc, AllArgs); - CheckConstructorCall(Constructor, + CheckConstructorCall(Constructor, DeclInitType, llvm::makeArrayRef(AllArgs.data(), AllArgs.size()), Proto, Loc); @@ -14879,11 +15593,13 @@ CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, return false; } -static QualType -RemoveAddressSpaceFromPtr(Sema &SemaRef, const PointerType *PtrTy) { - QualType QTy = PtrTy->getPointeeType(); - QTy = SemaRef.Context.removeAddrSpaceQualType(QTy); - return SemaRef.Context.getPointerType(QTy); +static CanQualType RemoveAddressSpaceFromPtr(Sema &SemaRef, + const PointerType *PtrTy) { + auto &Ctx = SemaRef.Context; + Qualifiers PtrQuals = PtrTy->getPointeeType().getQualifiers(); + PtrQuals.removeAddressSpace(); + return Ctx.getPointerType(Ctx.getCanonicalType(Ctx.getQualifiedType( + PtrTy->getPointeeType().getUnqualifiedType(), PtrQuals))); } static inline bool @@ -14895,24 +15611,27 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, QualType ResultType = FnDecl->getType()->castAs<FunctionType>()->getReturnType(); - // Check that the result type is not dependent. - if (ResultType->isDependentType()) - return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_new_delete_dependent_result_type) - << FnDecl->getDeclName() << ExpectedResultType; - - // The operator is valid on any address space for OpenCL. if (SemaRef.getLangOpts().OpenCLCPlusPlus) { - if (auto *PtrTy = ResultType->getAs<PointerType>()) { + // The operator is valid on any address space for OpenCL. + // Drop address space from actual and expected result types. + if (const auto *PtrTy = ResultType->getAs<PointerType>()) ResultType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy); - } + + if (auto ExpectedPtrTy = ExpectedResultType->getAs<PointerType>()) + ExpectedResultType = RemoveAddressSpaceFromPtr(SemaRef, ExpectedPtrTy); } // Check that the result type is what we expect. - if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) - return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_new_delete_invalid_result_type) - << FnDecl->getDeclName() << ExpectedResultType; + if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) { + // Reject even if the type is dependent; an operator delete function is + // required to have a non-dependent result type. + return SemaRef.Diag( + FnDecl->getLocation(), + ResultType->isDependentType() + ? diag::err_operator_new_delete_dependent_result_type + : diag::err_operator_new_delete_invalid_result_type) + << FnDecl->getDeclName() << ExpectedResultType; + } // A function template must have at least 2 parameters. if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2) @@ -14926,24 +15645,30 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, diag::err_operator_new_delete_too_few_parameters) << FnDecl->getDeclName(); - // Check the first parameter type is not dependent. QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); - if (FirstParamType->isDependentType()) - return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag) - << FnDecl->getDeclName() << ExpectedFirstParamType; - - // Check that the first parameter type is what we expect. if (SemaRef.getLangOpts().OpenCLCPlusPlus) { // The operator is valid on any address space for OpenCL. - if (auto *PtrTy = - FnDecl->getParamDecl(0)->getType()->getAs<PointerType>()) { + // Drop address space from actual and expected first parameter types. + if (const auto *PtrTy = + FnDecl->getParamDecl(0)->getType()->getAs<PointerType>()) FirstParamType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy); - } + + if (auto ExpectedPtrTy = ExpectedFirstParamType->getAs<PointerType>()) + ExpectedFirstParamType = + RemoveAddressSpaceFromPtr(SemaRef, ExpectedPtrTy); } + + // Check that the first parameter type is what we expect. if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != - ExpectedFirstParamType) - return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) - << FnDecl->getDeclName() << ExpectedFirstParamType; + ExpectedFirstParamType) { + // The first parameter type is not allowed to be dependent. As a tentative + // DR resolution, we allow a dependent parameter type if it is the right + // type anyway, to allow destroying operator delete in class templates. + return SemaRef.Diag(FnDecl->getLocation(), FirstParamType->isDependentType() + ? DependentParamTypeDiag + : InvalidParamTypeDiag) + << FnDecl->getDeclName() << ExpectedFirstParamType; + } return false; } @@ -15173,6 +15898,18 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef, SemaRef.Context.hasSameType(PmDecl->getType(), SemaRef.Context.CharTy)) return false; + // C++20 [over.literal]p5: + // A string literal operator template is a literal operator template + // whose template-parameter-list comprises a single non-type + // template-parameter of class type. + // + // As a DR resolution, we also allow placeholders for deduced class + // template specializations. + if (SemaRef.getLangOpts().CPlusPlus20 && + !PmDecl->isTemplateParameterPack() && + (PmDecl->getType()->isRecordType() || + PmDecl->getType()->getAs<DeducedTemplateSpecializationType>())) + return false; } else if (TemplateParams->size() == 2) { TemplateTypeParmDecl *PmType = dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(0)); @@ -15229,6 +15966,8 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { // template <char...> type operator "" name() and // template <class T, T...> type operator "" name() are the only valid // template signatures, and the only valid signatures with no parameters. + // + // C++20 also allows template <SomeClass T> type operator "" name(). if (TpDecl) { if (FnDecl->param_size() != 0) { Diag(FnDecl->getLocation(), @@ -15482,6 +16221,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; + if (!Invalid && Mode != 1 && BaseType->isSizelessType()) { + Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType; + Invalid = true; + } + if (!Invalid && !ExDeclType->isDependentType() && RequireNonAbstractType(Loc, ExDeclType, diag::err_abstract_type_in_decl, @@ -15653,9 +16397,10 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, AssertExpr = FullAssertExpr.get(); llvm::APSInt Cond; - if (!Failed && VerifyIntegerConstantExpression(AssertExpr, &Cond, - diag::err_static_assert_expression_is_not_constant, - /*AllowFold=*/false).isInvalid()) + if (!Failed && VerifyIntegerConstantExpression( + AssertExpr, &Cond, + diag::err_static_assert_expression_is_not_constant) + .isInvalid()) Failed = true; if (!Failed && !Cond) { @@ -15947,7 +16692,7 @@ 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::MemberContext); + Declarator TheDeclarator(DS, DeclaratorContext::Member); TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S); QualType T = TSI->getType(); if (TheDeclarator.isInvalidType()) @@ -16319,6 +17064,8 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, } } + warnOnReservedIdentifier(ND); + return ND; } @@ -16344,9 +17091,16 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { Diag(Prev->getLocation().isInvalid() ? DelLoc : Prev->getLocation(), Prev->isImplicit() ? diag::note_previous_implicit_declaration : diag::note_previous_declaration); + // We can't recover from this; the declaration might have already + // been used. + Fn->setInvalidDecl(); + return; } - // If the declaration wasn't the first, we delete the function anyway for - // recovery. + + // To maintain the invariant that functions are only deleted on their first + // declaration, mark the implicitly-instantiated declaration of the + // explicitly-specialized function as deleted instead of marking the + // instantiated redeclaration. Fn = Fn->getCanonicalDecl(); } @@ -16356,9 +17110,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { Fn->setInvalidDecl(); } - if (Fn->isDeleted()) - return; - // C++11 [basic.start.main]p3: // A program that defines main as deleted [...] is ill-formed. if (Fn->isMain()) @@ -16368,25 +17119,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // A deleted function is implicitly inline. Fn->setImplicitlyInline(); Fn->setDeletedAsWritten(); - - // See if we're deleting a function which is already known to override a - // non-deleted virtual function. - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { - bool IssuedDiagnostic = false; - for (const CXXMethodDecl *O : MD->overridden_methods()) { - if (!(*MD->begin_overridden_methods())->isDeleted()) { - if (!IssuedDiagnostic) { - Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName(); - IssuedDiagnostic = true; - } - Diag(O->getLocation(), diag::note_overridden_virtual_function); - } - } - // If this function was implicitly deleted because it was defaulted, - // explain why it was deleted. - if (IssuedDiagnostic && MD->isDefaulted()) - DiagnoseDeletedDefaultedFunction(MD); - } } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { @@ -16403,7 +17135,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { } Diag(DefaultLoc, diag::err_default_special_members) - << getLangOpts().CPlusPlus2a; + << getLangOpts().CPlusPlus20; return; } @@ -16417,14 +17149,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { (!isa<CXXConstructorDecl>(FD) && FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) { Diag(DefaultLoc, diag::err_default_special_members) - << getLangOpts().CPlusPlus2a; - return; - } - - if (DefKind.isComparison() && - !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { - Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class) - << (int)DefKind.asComparison(); + << getLangOpts().CPlusPlus20; return; } @@ -16432,7 +17157,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { // 'operator<=>' when parsing the '<=>' token. if (DefKind.isComparison() && DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) { - Diag(DefaultLoc, getLangOpts().CPlusPlus2a + Diag(DefaultLoc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_defaulted_comparison : diag::ext_defaulted_comparison); } @@ -16449,29 +17174,37 @@ 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()) + // If this is a comparison's defaulted definition within the record, do + // the checking when the record is complete. + if (DefKind.isComparison() && isa<CXXRecordDecl>(FD->getLexicalDeclContext())) 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 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; + } - if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember())) - MD->setInvalidDecl(); - else - DefineImplicitSpecialMember(*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())) + MD->setInvalidDecl(); + else + DefineDefaultedFunction(*this, MD, DefaultLoc); + } } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { @@ -16783,7 +17516,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 (LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsDevice && !isInOpenMPDeclareTargetContext() && !isInOpenMPTargetExecutionDirective()) { if (!DefinitionRequired) |