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