summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorRobert Nagy <robert@cvs.openbsd.org>2023-03-26 09:09:32 +0000
committerRobert Nagy <robert@cvs.openbsd.org>2023-03-26 09:09:32 +0000
commit37d96ad1fa72e9ee88c56559856736541a49735f (patch)
tree809ae57214a454ad42835ece63494e5078c8f24b /gnu
parent20adf64c6c91b1cb291ab3a7cf0cdc0aae4309b7 (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.td13
-rw-r--r--gnu/llvm/clang/lib/Sema/SemaDeclCXX.cpp2299
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)