[clang] 339a768 - Revert "Implement CWG2631"
Krasimir Georgiev via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 14 01:10:53 PST 2022
Author: Krasimir Georgiev
Date: 2022-12-14T09:10:22Z
New Revision: 339a7687e1c036a5f91c9d5391523b93e2e76cd3
URL: https://github.com/llvm/llvm-project/commit/339a7687e1c036a5f91c9d5391523b93e2e76cd3
DIFF: https://github.com/llvm/llvm-project/commit/339a7687e1c036a5f91c9d5391523b93e2e76cd3.diff
LOG: Revert "Implement CWG2631"
This reverts commit f1f1b60c7ba607e9ffe3bc012161d43ef95ac773.
Temporary revert, possibly triggers a new assertion failure on
QualType::getCommonPtr.
We're working on a reproducer, to follow-up on
https://reviews.llvm.org/D136554.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/ExprCXX.h
clang/include/clang/AST/Stmt.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/ExprCXX.cpp
clang/lib/Parse/ParseCXXInlineMethods.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Sema/UsedDeclVisitor.h
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/CXX/class/class.local/p1-0x.cpp
clang/test/CXX/drs/dr26xx.cpp
clang/test/CodeGenCXX/builtin-source-location.cpp
clang/test/SemaCXX/cxx11-default-member-initializers.cpp
clang/test/SemaCXX/source_location.cpp
clang/www/cxx_dr_status.html
Removed:
clang/test/CodeGenCXX/default-arguments-with-immediate.cpp
clang/test/CodeGenCXX/meminit-initializers-odr.cpp
clang/test/PCH/default-argument-with-immediate-calls.cpp
clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 73f2962ff2fc7..cad59b0ce5def 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -645,11 +645,6 @@ C++ Language Changes in Clang
- Implemented DR2358 allowing init captures in lambdas in default arguments.
- implemented `DR2654 <https://wg21.link/cwg2654>`_ which undeprecates
all compound assignements operations on volatile qualified variables.
-- Implemented DR2631. Invalid ``consteval`` calls in default arguments and default
- member initializers are diagnosed when and if the default is used.
- This Fixes `Issue 56379 <https://github.com/llvm/llvm-project/issues/56379>`_
- and changes the value of ``std::source_location::current()``
- used in default parameters calls compared to previous versions of Clang.
C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index e99ebe6126824..c2f6751d62ede 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -1244,12 +1244,8 @@ class CXXThrowExpr : public Expr {
/// This wraps up a function call argument that was created from the
/// corresponding parameter's default argument, when the call did not
/// explicitly supply arguments for all of the parameters.
-class CXXDefaultArgExpr final
- : public Expr,
- private llvm::TrailingObjects<CXXDefaultArgExpr, Expr *> {
+class CXXDefaultArgExpr final : public Expr {
friend class ASTStmtReader;
- friend class ASTReader;
- friend TrailingObjects;
/// The parameter whose default is being used.
ParmVarDecl *Param;
@@ -1258,7 +1254,7 @@ class CXXDefaultArgExpr final
DeclContext *UsedContext;
CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *Param,
- Expr *RewrittenExpr, DeclContext *UsedContext)
+ DeclContext *UsedContext)
: Expr(SC,
Param->hasUnparsedDefaultArg()
? Param->getType().getNonReferenceType()
@@ -1267,58 +1263,28 @@ class CXXDefaultArgExpr final
Param->getDefaultArg()->getObjectKind()),
Param(Param), UsedContext(UsedContext) {
CXXDefaultArgExprBits.Loc = Loc;
- CXXDefaultArgExprBits.HasRewrittenInit = RewrittenExpr != nullptr;
- if (RewrittenExpr)
- *getTrailingObjects<Expr *>() = RewrittenExpr;
setDependence(computeDependence(this));
}
- CXXDefaultArgExpr(EmptyShell Empty, bool HasRewrittenInit)
- : Expr(CXXDefaultArgExprClass, Empty) {
- CXXDefaultArgExprBits.HasRewrittenInit = HasRewrittenInit;
- }
-
- size_t numTrailingObjects() const {
- return CXXDefaultArgExprBits.HasRewrittenInit;
- }
-
public:
- static CXXDefaultArgExpr *CreateEmpty(const ASTContext &C,
- bool HasRewrittenInit);
+ CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
// \p Param is the parameter whose default argument is used by this
// expression.
static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
- ParmVarDecl *Param, Expr *RewrittenExpr,
- DeclContext *UsedContext);
+ ParmVarDecl *Param,
+ DeclContext *UsedContext) {
+ return new (C)
+ CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, UsedContext);
+ }
+
// Retrieve the parameter that the argument was created from.
const ParmVarDecl *getParam() const { return Param; }
ParmVarDecl *getParam() { return Param; }
- bool hasRewrittenInit() const {
- return CXXDefaultArgExprBits.HasRewrittenInit;
- }
-
- // Retrieve the argument to the function call.
- Expr *getExpr();
- const Expr *getExpr() const {
- return const_cast<CXXDefaultArgExpr *>(this)->getExpr();
- }
-
- Expr *getRewrittenExpr() {
- return hasRewrittenInit() ? *getTrailingObjects<Expr *>() : nullptr;
- }
-
- const Expr *getRewrittenExpr() const {
- return const_cast<CXXDefaultArgExpr *>(this)->getRewrittenExpr();
- }
-
- // Retrieve the rewritten init expression (for an init expression containing
- // immediate calls) with the top level FullExpr and ConstantExpr stripped off.
- Expr *getAdjustedRewrittenExpr();
- const Expr *getAdjustedRewrittenExpr() const {
- return const_cast<CXXDefaultArgExpr *>(this)->getAdjustedRewrittenExpr();
- }
+ // Retrieve the actual argument to the function call.
+ const Expr *getExpr() const { return getParam()->getDefaultArg(); }
+ Expr *getExpr() { return getParam()->getDefaultArg(); }
const DeclContext *getUsedContext() const { return UsedContext; }
DeclContext *getUsedContext() { return UsedContext; }
@@ -1355,13 +1321,10 @@ class CXXDefaultArgExpr final
/// is implicitly used in a mem-initializer-list in a constructor
/// (C++11 [class.base.init]p8) or in aggregate initialization
/// (C++1y [dcl.init.aggr]p7).
-class CXXDefaultInitExpr final
- : public Expr,
- private llvm::TrailingObjects<CXXDefaultArgExpr, Expr *> {
-
- friend class ASTStmtReader;
+class CXXDefaultInitExpr : public Expr {
friend class ASTReader;
- friend TrailingObjects;
+ friend class ASTStmtReader;
+
/// The field whose default is being used.
FieldDecl *Field;
@@ -1369,29 +1332,16 @@ class CXXDefaultInitExpr final
DeclContext *UsedContext;
CXXDefaultInitExpr(const ASTContext &Ctx, SourceLocation Loc,
- FieldDecl *Field, QualType Ty, DeclContext *UsedContext,
- Expr *RewrittenInitExpr);
-
- CXXDefaultInitExpr(EmptyShell Empty, bool HasRewrittenInit)
- : Expr(CXXDefaultInitExprClass, Empty) {
- CXXDefaultInitExprBits.HasRewrittenInit = HasRewrittenInit;
- }
+ FieldDecl *Field, QualType Ty, DeclContext *UsedContext);
- size_t numTrailingObjects() const {
- return CXXDefaultInitExprBits.HasRewrittenInit;
- }
+ CXXDefaultInitExpr(EmptyShell Empty) : Expr(CXXDefaultInitExprClass, Empty) {}
public:
- static CXXDefaultInitExpr *CreateEmpty(const ASTContext &C,
- bool HasRewrittenInit);
/// \p Field is the non-static data member whose default initializer is used
/// by this expression.
static CXXDefaultInitExpr *Create(const ASTContext &Ctx, SourceLocation Loc,
- FieldDecl *Field, DeclContext *UsedContext,
- Expr *RewrittenInitExpr);
-
- bool hasRewrittenInit() const {
- return CXXDefaultInitExprBits.HasRewrittenInit;
+ FieldDecl *Field, DeclContext *UsedContext) {
+ return new (Ctx) CXXDefaultInitExpr(Ctx, Loc, Field, Field->getType(), UsedContext);
}
/// Get the field whose initializer will be used.
@@ -1399,23 +1349,13 @@ class CXXDefaultInitExpr final
const FieldDecl *getField() const { return Field; }
/// Get the initialization expression that will be used.
- Expr *getExpr();
const Expr *getExpr() const {
- return const_cast<CXXDefaultInitExpr *>(this)->getExpr();
- }
-
- /// Retrieve the initializing expression with evaluated immediate calls, if
- /// any.
- const Expr *getRewrittenExpr() const {
- assert(hasRewrittenInit() && "expected a rewritten init expression");
- return *getTrailingObjects<Expr *>();
+ assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
+ return Field->getInClassInitializer();
}
-
- /// Retrieve the initializing expression with evaluated immediate calls, if
- /// any.
- Expr *getRewrittenExpr() {
- assert(hasRewrittenInit() && "expected a rewritten init expression");
- return *getTrailingObjects<Expr *>();
+ Expr *getExpr() {
+ assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
+ return Field->getInClassInitializer();
}
const DeclContext *getUsedContext() const { return UsedContext; }
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 8781c70abfa26..619d85664476a 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -690,9 +690,6 @@ class alignas(void *) Stmt {
unsigned : NumExprBits;
- /// Whether this CXXDefaultArgExpr rewrote its argument and stores a copy.
- unsigned HasRewrittenInit : 1;
-
/// The location where the default argument expression was used.
SourceLocation Loc;
};
@@ -703,10 +700,6 @@ class alignas(void *) Stmt {
unsigned : NumExprBits;
- /// Whether this CXXDefaultInitExprBitfields rewrote its argument and stores
- /// a copy.
- unsigned HasRewrittenInit : 1;
-
/// The location where the default initializer expression was used.
SourceLocation Loc;
};
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fb071fc20b0d5..c9f5bb28283cf 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2646,10 +2646,6 @@ def err_invalid_consteval_take_address : Error<
" of an immediate invocation">;
def err_invalid_consteval_call : Error<
"call to consteval function %q0 is not a constant expression">;
-def note_invalid_consteval_initializer : Note<
- "in the default initalizer of %0">;
-def note_invalid_consteval_initializer_here : Note<
- "initialized here %0">;
def err_invalid_consteval_decl_kind : Error<
"%0 cannot be declared consteval">;
def err_invalid_constexpr : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7e9b32d4ea995..3c0dee4b6ed93 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1330,25 +1330,6 @@ class Sema final {
bool InDiscardedStatement;
bool InImmediateFunctionContext;
- bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
-
- // When evaluating immediate functions in the initializer of a default
- // argument or default member initializer, this is the declaration whose
- // default initializer is being evaluated and the location of the call
- // or constructor definition.
- struct InitializationContext {
- InitializationContext(SourceLocation Loc, ValueDecl *Decl,
- DeclContext *Context)
- : Loc(Loc), Decl(Decl), Context(Context) {
- assert(Decl && Context && "invalid initialization context");
- }
-
- SourceLocation Loc;
- ValueDecl *Decl = nullptr;
- DeclContext *Context = nullptr;
- };
- llvm::Optional<InitializationContext> DelayedDefaultInitializationContext;
-
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
CleanupInfo ParentCleanup,
@@ -6227,22 +6208,19 @@ class Sema final {
bool IsStdInitListInitialization, bool RequiresZeroInit,
unsigned ConstructKind, SourceRange ParenRange);
- ExprResult ConvertMemberDefaultInitExpression(FieldDecl *FD, Expr *InitExpr,
- SourceLocation InitLoc);
-
ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field);
/// Instantiate or parse a C++ default argument expression as necessary.
/// Return true on error.
bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param, Expr *Init = nullptr,
- bool SkipImmediateInvocations = true);
+ ParmVarDecl *Param);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
- ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param, Expr *Init = nullptr);
+ ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc,
+ FunctionDecl *FD,
+ ParmVarDecl *Param);
/// FinalizeVarWithDestructor - Prepare for calling destructor on the
/// constructed variable.
@@ -9649,63 +9627,6 @@ class Sema final {
return ExprEvalContexts.back().isImmediateFunctionContext();
}
- bool isCheckingDefaultArgumentOrInitializer() const {
- assert(!ExprEvalContexts.empty() &&
- "Must be in an expression evaluation context");
- const ExpressionEvaluationContextRecord &Ctx = ExprEvalContexts.back();
- return (Ctx.Context ==
- ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed) ||
- Ctx.IsCurrentlyCheckingDefaultArgumentOrInitializer;
- }
-
- bool isCheckingDefaultArgumentOrInitializerOfOuterEntity() const {
- assert(!ExprEvalContexts.empty() &&
- "Must be in an expression evaluation context");
- for (const auto &Ctx : llvm::reverse(ExprEvalContexts)) {
- if ((Ctx.Context ==
- ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed) ||
- Ctx.IsCurrentlyCheckingDefaultArgumentOrInitializer)
- return true;
- if (Ctx.isConstantEvaluated() || Ctx.isImmediateFunctionContext() ||
- Ctx.isUnevaluated())
- return false;
- }
- return false;
- }
-
- llvm::Optional<ExpressionEvaluationContextRecord::InitializationContext>
- InnermostDeclarationWithDelayedImmediateInvocations() const {
- assert(!ExprEvalContexts.empty() &&
- "Must be in an expression evaluation context");
- for (const auto &Ctx : llvm::reverse(ExprEvalContexts)) {
- if (Ctx.Context == ExpressionEvaluationContext::PotentiallyEvaluated &&
- Ctx.DelayedDefaultInitializationContext)
- return Ctx.DelayedDefaultInitializationContext;
- if (Ctx.isConstantEvaluated() || Ctx.isImmediateFunctionContext() ||
- Ctx.isUnevaluated())
- break;
- }
- return std::nullopt;
- }
-
- llvm::Optional<ExpressionEvaluationContextRecord::InitializationContext>
- OutermostDeclarationWithDelayedImmediateInvocations() const {
- assert(!ExprEvalContexts.empty() &&
- "Must be in an expression evaluation context");
- llvm::Optional<ExpressionEvaluationContextRecord::InitializationContext>
- Res;
- for (auto &Ctx : llvm::reverse(ExprEvalContexts)) {
- if (Ctx.Context == ExpressionEvaluationContext::PotentiallyEvaluated &&
- !Ctx.DelayedDefaultInitializationContext && Res)
- break;
- if (Ctx.isConstantEvaluated() || Ctx.isImmediateFunctionContext() ||
- Ctx.isUnevaluated())
- break;
- Res = Ctx.DelayedDefaultInitializationContext;
- }
- return Res;
- }
-
/// RAII class used to determine whether SFINAE has
/// trapped any errors that occur during template argument
/// deduction.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index bdfa0d218b171..e5704b39b60ee 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7687,16 +7687,9 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (Error Err = ImportDefaultArgOfParmVarDecl(*FromParam, ToParam))
return std::move(Err);
}
- Expr *RewrittenInit = nullptr;
- if (E->hasRewrittenInit()) {
- ExpectedExpr ExprOrErr = import(E->getExpr());
- if (!ExprOrErr)
- return ExprOrErr.takeError();
- RewrittenInit = ExprOrErr.get();
- }
+
return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
- *ToParamOrErr, RewrittenInit,
- *UsedContextOrErr);
+ *ToParamOrErr, *UsedContextOrErr);
}
ExpectedStmt
@@ -8388,16 +8381,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
ToField->setInClassInitializer(*ToInClassInitializerOrErr);
}
- Expr *RewrittenInit = nullptr;
- if (E->hasRewrittenInit()) {
- ExpectedExpr ExprOrErr = import(E->getExpr());
- if (!ExprOrErr)
- return ExprOrErr.takeError();
- RewrittenInit = ExprOrErr.get();
- }
-
return CXXDefaultInitExpr::Create(Importer.getToContext(), *ToBeginLocOrErr,
- ToField, *UsedContextOrErr, RewrittenInit);
+ ToField, *UsedContextOrErr);
}
ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 52c7763243beb..b1fdc897bf27e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2887,7 +2887,8 @@ Expr *ParmVarDecl::getDefaultArg() {
Expr *Arg = getInit();
if (auto *E = dyn_cast_or_null<FullExpr>(Arg))
- return E->getSubExpr();
+ if (!isa<ConstantExpr>(E))
+ return E->getSubExpr();
return Arg;
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 8ed95267659f6..b988f0fe13f7f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -949,43 +949,9 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
}
-CXXDefaultArgExpr *CXXDefaultArgExpr::CreateEmpty(const ASTContext &C,
- bool HasRewrittenInit) {
- size_t Size = totalSizeToAlloc<Expr *>(HasRewrittenInit);
- auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
- return new (Mem) CXXDefaultArgExpr(EmptyShell(), HasRewrittenInit);
-}
-
-CXXDefaultArgExpr *CXXDefaultArgExpr::Create(const ASTContext &C,
- SourceLocation Loc,
- ParmVarDecl *Param,
- Expr *RewrittenExpr,
- DeclContext *UsedContext) {
- size_t Size = totalSizeToAlloc<Expr *>(RewrittenExpr != nullptr);
- auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
- return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
- RewrittenExpr, UsedContext);
-}
-
-Expr *CXXDefaultArgExpr::getExpr() {
- return CXXDefaultArgExprBits.HasRewrittenInit ? getAdjustedRewrittenExpr()
- : getParam()->getDefaultArg();
-}
-
-Expr *CXXDefaultArgExpr::getAdjustedRewrittenExpr() {
- assert(hasRewrittenInit() &&
- "expected this CXXDefaultArgExpr to have a rewritten init.");
- Expr *Init = getRewrittenExpr();
- if (auto *E = dyn_cast_if_present<FullExpr>(Init))
- if (!isa<ConstantExpr>(E))
- return E->getSubExpr();
- return Init;
-}
-
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
SourceLocation Loc, FieldDecl *Field,
- QualType Ty, DeclContext *UsedContext,
- Expr *RewrittenInitExpr)
+ QualType Ty, DeclContext *UsedContext)
: Expr(CXXDefaultInitExprClass, Ty.getNonLValueExprType(Ctx),
Ty->isLValueReferenceType() ? VK_LValue
: Ty->isRValueReferenceType() ? VK_XValue
@@ -993,43 +959,11 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
/*FIXME*/ OK_Ordinary),
Field(Field), UsedContext(UsedContext) {
CXXDefaultInitExprBits.Loc = Loc;
- CXXDefaultInitExprBits.HasRewrittenInit = RewrittenInitExpr != nullptr;
-
- if (CXXDefaultInitExprBits.HasRewrittenInit)
- *getTrailingObjects<Expr *>() = RewrittenInitExpr;
-
assert(Field->hasInClassInitializer());
setDependence(computeDependence(this));
}
-CXXDefaultInitExpr *CXXDefaultInitExpr::CreateEmpty(const ASTContext &C,
- bool HasRewrittenInit) {
- size_t Size = totalSizeToAlloc<Expr *>(HasRewrittenInit);
- auto *Mem = C.Allocate(Size, alignof(CXXDefaultInitExpr));
- return new (Mem) CXXDefaultInitExpr(EmptyShell(), HasRewrittenInit);
-}
-
-CXXDefaultInitExpr *CXXDefaultInitExpr::Create(const ASTContext &Ctx,
- SourceLocation Loc,
- FieldDecl *Field,
- DeclContext *UsedContext,
- Expr *RewrittenInitExpr) {
-
- size_t Size = totalSizeToAlloc<Expr *>(RewrittenInitExpr != nullptr);
- auto *Mem = Ctx.Allocate(Size, alignof(CXXDefaultArgExpr));
- return new (Mem) CXXDefaultInitExpr(Ctx, Loc, Field, Field->getType(),
- UsedContext, RewrittenInitExpr);
-}
-
-Expr *CXXDefaultInitExpr::getExpr() {
- assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
- if (hasRewrittenInit())
- return getRewrittenExpr();
-
- return Field->getInClassInitializer();
-}
-
CXXTemporary *CXXTemporary::Create(const ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 3a7f5426d4a70..d918ea26b9d9d 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -648,11 +648,6 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
Actions.ActOnStartCXXInClassMemberInitializer();
- // The initializer isn't actually potentially evaluated unless it is
- // used.
- EnterExpressionEvaluationContext Eval(
- Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed);
-
ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false,
EqualLoc);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8fb6673b0a45a..53afdd7e7291d 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3188,11 +3188,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
"Data member initializer not starting with '=' or '{'");
EnterExpressionEvaluationContext Context(
- Actions,
- isa_and_present<FieldDecl>(D)
- ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
- : Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
- D);
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D);
if (TryConsumeToken(tok::equal, EqualLoc)) {
if (Tok.is(tok::kw_delete)) {
// In principle, an initializer of '= delete p;' is legal, but it will
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 60c3ca7125016..9a80a4874b6db 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4059,21 +4059,6 @@ 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.
@@ -4102,13 +4087,31 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
ExprResult Init = InitExpr;
if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- Init = ConvertMemberDefaultInitExpression(FD, InitExpr, 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);
+ Init = Seq.Perform(*this, Entity, Kind, InitExpr);
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);
@@ -15648,6 +15651,70 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
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
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e568cc5ca0546..e16f07d418112 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5860,10 +5860,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param, Expr *RewrittenInit,
- bool SkipImmediateInvocations) {
+ ParmVarDecl *Param) {
if (Param->hasUnparsedDefaultArg()) {
- assert(!RewrittenInit && "Should not have a rewritten init expression yet");
// If we've already cleared out the location for the default argument,
// that means we're parsing it right now.
if (!UnparsedDefaultArgLocs.count(Param)) {
@@ -5880,14 +5878,11 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
return true;
}
- if (Param->hasUninstantiatedDefaultArg()) {
- assert(!RewrittenInit && "Should not have a rewitten init expression yet");
- if (InstantiateDefaultArgument(CallLoc, FD, Param))
- return true;
- }
+ if (Param->hasUninstantiatedDefaultArg() &&
+ InstantiateDefaultArgument(CallLoc, FD, Param))
+ return true;
- Expr *Init = RewrittenInit ? RewrittenInit : Param->getInit();
- assert(Init && "default argument but no initializer?");
+ assert(Param->hasInit() && "default argument but no initializer?");
// If the default expression creates temporaries, we need to
// push them to the current stack of expression temporaries so they'll
@@ -5896,254 +5891,34 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// bound temporaries; see the comment in PR5810.
// We don't need to do that with block decls, though, because
// blocks in default argument expression can never capture anything.
- if (auto *InitWithCleanup = dyn_cast<ExprWithCleanups>(Init)) {
+ if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) {
// Set the "needs cleanups" bit regardless of whether there are
// any explicit objects.
- Cleanup.setExprNeedsCleanups(InitWithCleanup->cleanupsHaveSideEffects());
+ Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects());
+
// Append all the objects to the cleanup list. Right now, this
// should always be a no-op, because blocks in default argument
// expressions should never be able to capture anything.
- assert(!InitWithCleanup->getNumObjects() &&
+ assert(!Init->getNumObjects() &&
"default argument expression has capturing blocks?");
}
+
+ // We already type-checked the argument, so we know it works.
+ // Just mark all of the declarations in this potentially-evaluated expression
+ // as being "referenced".
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
- ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
- SkipImmediateInvocations;
- MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables*/ true);
+ MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
+ /*SkipLocalVariables=*/true);
return false;
}
-struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> {
- bool HasImmediateCalls = false;
-
- bool shouldVisitImplicitCode() const { return true; }
-
- bool VisitCallExpr(CallExpr *E) {
- if (const FunctionDecl *FD = E->getDirectCallee())
- HasImmediateCalls |= FD->isConsteval();
- return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
- }
-
- // SourceLocExpr are not immediate invocations
- // but CXXDefaultInitExpr/CXXDefaultArgExpr containing a SourceLocExpr
- // need to be rebuilt so that they refer to the correct SourceLocation and
- // DeclContext.
- bool VisitSourceLocExpr(SourceLocExpr *E) {
- HasImmediateCalls = true;
- return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
- }
-
- // A nested lambda might have parameters with immediate invocations
- // in their default arguments.
- // The compound statement is not visited (as it does not constitute a
- // subexpression).
- // FIXME: We should consider visiting and transforming captures
- // with init expressions.
- bool VisitLambdaExpr(LambdaExpr *E) {
- return VisitCXXMethodDecl(E->getCallOperator());
- }
-
- // Blocks don't support default parameters, and, as for lambdas,
- // we don't consider their body a subexpression.
- bool VisitBlockDecl(BlockDecl *B) { return false; }
-
- bool VisitCompoundStmt(CompoundStmt *B) { return false; }
-
- bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
- return TraverseStmt(E->getExpr());
- }
-
- bool VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
- return TraverseStmt(E->getExpr());
- }
-};
-
-struct EnsureImmediateInvocationInDefaultArgs
- : TreeTransform<EnsureImmediateInvocationInDefaultArgs> {
- EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef)
- : TreeTransform(SemaRef) {}
-
- // Lambda can only have immediate invocations in the default
- // args of their parameters, which is transformed upon calling the closure.
- // The body is not a subexpression, so we have nothing to do.
- // FIXME: Immediate calls in capture initializers should be transformed.
- ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; }
- ExprResult TransformBlockExpr(BlockExpr *E) { return E; }
-};
-
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
- FunctionDecl *FD, ParmVarDecl *Param,
- Expr *Init) {
+ FunctionDecl *FD, ParmVarDecl *Param) {
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
-
- bool NestedDefaultChecking =
- isCheckingDefaultArgumentOrInitializerOfOuterEntity();
-
- llvm::Optional<ExpressionEvaluationContextRecord::InitializationContext>
- InitializationContext =
- OutermostDeclarationWithDelayedImmediateInvocations();
- if (!InitializationContext.has_value())
- InitializationContext.emplace(CallLoc, Param, CurContext);
-
- if (!Init && !Param->hasUnparsedDefaultArg()) {
- // Mark that we are replacing a default argument first.
- // If we are instantiating a template we won't have to
- // retransform immediate calls.
- EnterExpressionEvaluationContext EvalContext(
- *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
-
- if (Param->hasUninstantiatedDefaultArg()) {
- if (InstantiateDefaultArgument(CallLoc, FD, Param))
- return ExprError();
- }
- // CWG2631
- // An immediate invocation that is not evaluated where it appears is
- // evaluated and checked for whether it is a constant expression at the
- // point where the enclosing initializer is used in a function call.
- ImmediateCallVisitor V;
- if (!NestedDefaultChecking)
- V.TraverseDecl(Param);
- if (V.HasImmediateCalls) {
- ExprEvalContexts.back().DelayedDefaultInitializationContext = {
- CallLoc, Param, CurContext};
- EnsureImmediateInvocationInDefaultArgs Immediate(*this);
- ExprResult Res = Immediate.TransformInitializer(Param->getInit(),
- /*NotCopy=*/false);
- if (Res.isInvalid())
- return ExprError();
- Res = ConvertParamDefaultArgument(Param, Res.get(),
- Res.get()->getBeginLoc());
- if (Res.isInvalid())
- return ExprError();
- Init = Res.get();
- }
- }
-
- if (CheckCXXDefaultArgExpr(
- CallLoc, FD, Param, Init,
- /*SkipImmediateInvocations=*/NestedDefaultChecking))
+ if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
return ExprError();
-
- return CXXDefaultArgExpr::Create(Context, InitializationContext->Loc, Param,
- Init, InitializationContext->Context);
-}
-
-ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
- assert(Field->hasInClassInitializer());
-
- // If we might have already tried and failed to instantiate, don't try again.
- if (Field->isInvalidDecl())
- return ExprError();
-
- auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());
-
- llvm::Optional<ExpressionEvaluationContextRecord::InitializationContext>
- InitializationContext =
- OutermostDeclarationWithDelayedImmediateInvocations();
- if (!InitializationContext.has_value())
- InitializationContext.emplace(Loc, Field, CurContext);
-
- Expr *Init = nullptr;
-
- bool NestedDefaultChecking =
- isCheckingDefaultArgumentOrInitializerOfOuterEntity();
-
- EnterExpressionEvaluationContext EvalContext(
- *this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
-
- if (!Field->getInClassInitializer()) {
- // Maybe we haven't instantiated the in-class initializer. Go check the
- // pattern FieldDecl to see if it has one.
- if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
- CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
- DeclContext::lookup_result Lookup =
- ClassPattern->lookup(Field->getDeclName());
-
- FieldDecl *Pattern = nullptr;
- for (auto *L : Lookup) {
- if ((Pattern = dyn_cast<FieldDecl>(L)))
- break;
- }
- assert(Pattern && "We must have set the Pattern!");
- if (!Pattern->hasInClassInitializer() ||
- InstantiateInClassInitializer(Loc, Field, Pattern,
- getTemplateInstantiationArgs(Field))) {
- Field->setInvalidDecl();
- return ExprError();
- }
- }
- }
-
- // CWG2631
- // An immediate invocation that is not evaluated where it appears is
- // evaluated and checked for whether it is a constant expression at the
- // point where the enclosing initializer is used in a [...] a constructor
- // definition, or an aggregate initialization.
- ImmediateCallVisitor V;
- if (!NestedDefaultChecking)
- V.TraverseDecl(Field);
- if (V.HasImmediateCalls) {
- ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
- CurContext};
- ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
- NestedDefaultChecking;
-
- EnsureImmediateInvocationInDefaultArgs Immediate(*this);
- ExprResult Res =
- Immediate.TransformInitializer(Field->getInClassInitializer(),
- /*CXXDirectInit=*/false);
- if (!Res.isInvalid())
- Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
- if (Res.isInvalid()) {
- Field->setInvalidDecl();
- return ExprError();
- }
- Init = Res.get();
- }
-
- if (Field->getInClassInitializer()) {
- Expr *E = Init ? Init : Field->getInClassInitializer();
- if (!NestedDefaultChecking)
- MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false);
- // C++11 [class.base.init]p7:
- // The initialization of each base and member constitutes a
- // full-expression.
- ExprResult Res = ActOnFinishFullExpr(E, /*DiscardedValue=*/false);
- if (Res.isInvalid()) {
- Field->setInvalidDecl();
- return ExprError();
- }
- Init = Res.get();
-
- return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc,
- Field, InitializationContext->Context,
- Init);
- }
-
- // 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();
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
}
Sema::VariadicCallType
@@ -17770,7 +17545,6 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
!Decl->isConsteval() || isConstantEvaluated() ||
- isCheckingDefaultArgumentOrInitializer() ||
RebuildingImmediateInvocation || isImmediateFunctionContext())
return E;
@@ -17816,14 +17590,8 @@ static void EvaluateAndDiagnoseImmediateInvocation(
FD = Call->getConstructor();
else
llvm_unreachable("unhandled decl kind");
- assert(FD && FD->isConsteval());
+ assert(FD->isConsteval());
SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD;
- if (auto Context =
- SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) {
- SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer)
- << Context->Decl;
- SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at);
- }
for (auto &Note : Notes)
SemaRef.Diag(Note.first, Note.second);
return;
@@ -19969,8 +19737,7 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
if (!isUnevaluatedContext() && !isConstantEvaluated() &&
- !isImmediateFunctionContext() &&
- !isCheckingDefaultArgumentOrInitializer() && FD->isConsteval() &&
+ !isImmediateFunctionContext() && FD->isConsteval() &&
!RebuildingImmediateInvocation && !FD->isDependentContext())
ExprEvalContexts.back().ReferenceToConsteval.insert(E);
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 11f920ccd2d2f..0c8ae8a927c28 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1979,9 +1979,9 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())->
getDescribedFunctionTemplate() &&
"Default arg expressions are never formed in dependent cases.");
- return SemaRef.BuildCXXDefaultArgExpr(
- E->getUsedLocation(), cast<FunctionDecl>(E->getParam()->getDeclContext()),
- E->getParam());
+ return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(),
+ cast<FunctionDecl>(E->getParam()->getDeclContext()),
+ E->getParam());
}
template<typename Fn>
@@ -3408,8 +3408,6 @@ bool Sema::InstantiateInClassInitializer(
ContextRAII SavedContext(*this, Instantiation->getParent());
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
- ExprEvalContexts.back().DelayedDefaultInitializationContext = {
- PointOfInstantiation, Instantiation, CurContext};
LocalInstantiationScope Scope(*this, true);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 846efc8f32978..d94b64a2a7a0d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3210,10 +3210,9 @@ class TreeTransform {
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide
diff erent behavior.
- ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param,
- Expr *RewrittenExpr) {
+ ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) {
return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param,
- RewrittenExpr, getSema().CurContext);
+ getSema().CurContext);
}
/// Build a new C++11 default-initialization expression.
@@ -3223,7 +3222,8 @@ class TreeTransform {
/// routine to provide
diff erent behavior.
ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc,
FieldDecl *Field) {
- return getSema().BuildCXXDefaultInitExpr(Loc, Field);
+ return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field,
+ getSema().CurContext);
}
/// Build a new C++ zero-initialization expression.
@@ -12162,20 +12162,11 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!Param)
return ExprError();
- ExprResult InitRes;
- if (E->hasRewrittenInit()) {
- InitRes = getDerived().TransformExpr(E->getRewrittenExpr());
- if (InitRes.isInvalid())
- return ExprError();
- }
-
if (!getDerived().AlwaysRebuild() && Param == E->getParam() &&
- E->getUsedContext() == SemaRef.CurContext &&
- InitRes.get() == E->getRewrittenExpr())
+ E->getUsedContext() == SemaRef.CurContext)
return E;
- return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param,
- InitRes.get());
+ return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
}
template<typename Derived>
diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h
index 580d702f96fe5..24b7342b3fb40 100644
--- a/clang/lib/Sema/UsedDeclVisitor.h
+++ b/clang/lib/Sema/UsedDeclVisitor.h
@@ -82,28 +82,11 @@ class UsedDeclVisitor : public EvaluatedExprVisitor<Derived> {
void VisitCXXConstructExpr(CXXConstructExpr *E) {
asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor());
- CXXConstructorDecl *D = E->getConstructor();
- for (const CXXCtorInitializer *Init : D->inits()) {
- if (Init->isInClassMemberInitializer())
- asImpl().Visit(Init->getInit());
- }
Inherited::VisitCXXConstructExpr(E);
}
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
asImpl().Visit(E->getExpr());
- Inherited::VisitCXXDefaultArgExpr(E);
- }
-
- void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
- asImpl().Visit(E->getExpr());
- Inherited::VisitCXXDefaultInitExpr(E);
- }
-
- void VisitInitListExpr(InitListExpr *ILE) {
- if (ILE->hasArrayFiller())
- asImpl().Visit(ILE->getArrayFiller());
- Inherited::VisitInitListExpr(ILE);
}
void visitUsedDecl(SourceLocation Loc, Decl *D) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 08f9f0bf50d03..2a3c6e7231785 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1824,9 +1824,6 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
E->Param = readDeclAs<ParmVarDecl>();
E->UsedContext = readDeclAs<DeclContext>();
E->CXXDefaultArgExprBits.Loc = readSourceLocation();
- E->CXXDefaultArgExprBits.HasRewrittenInit = Record.readInt();
- if (E->CXXDefaultArgExprBits.HasRewrittenInit)
- *E->getTrailingObjects<Expr *>() = Record.readSubExpr();
}
void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
@@ -1834,9 +1831,6 @@ void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
E->Field = readDeclAs<FieldDecl>();
E->UsedContext = readDeclAs<DeclContext>();
E->CXXDefaultInitExprBits.Loc = readSourceLocation();
- E->CXXDefaultInitExprBits.HasRewrittenInit = Record.readInt();
- if (E->CXXDefaultInitExprBits.HasRewrittenInit)
- *E->getTrailingObjects<Expr *>() = Record.readSubExpr();
}
void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
@@ -3835,13 +3829,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CXX_DEFAULT_ARG:
- S = CXXDefaultArgExpr::CreateEmpty(
- Context, /*HasRewrittenInit=*/Record[ASTStmtReader::NumExprFields]);
+ S = new (Context) CXXDefaultArgExpr(Empty);
break;
case EXPR_CXX_DEFAULT_INIT:
- S = CXXDefaultInitExpr::CreateEmpty(
- Context, /*HasRewrittenInit=*/Record[ASTStmtReader::NumExprFields]);
+ S = new (Context) CXXDefaultInitExpr(Empty);
break;
case EXPR_CXX_BIND_TEMPORARY:
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 6e4101ac122ee..e2ba69ca1eec8 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1745,9 +1745,6 @@ void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Record.AddDeclRef(E->getParam());
Record.AddDeclRef(cast_or_null<Decl>(E->getUsedContext()));
Record.AddSourceLocation(E->getUsedLocation());
- Record.push_back(E->hasRewrittenInit());
- if (E->hasRewrittenInit())
- Record.AddStmt(E->getRewrittenExpr());
Code = serialization::EXPR_CXX_DEFAULT_ARG;
}
@@ -1756,9 +1753,6 @@ void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
Record.AddDeclRef(E->getField());
Record.AddDeclRef(cast_or_null<Decl>(E->getUsedContext()));
Record.AddSourceLocation(E->getExprLoc());
- Record.push_back(E->hasRewrittenInit());
- if (E->hasRewrittenInit())
- Record.AddStmt(E->getRewrittenExpr());
Code = serialization::EXPR_CXX_DEFAULT_INIT;
}
diff --git a/clang/test/CXX/class/class.local/p1-0x.cpp b/clang/test/CXX/class/class.local/p1-0x.cpp
index 096f5080099ec..49125f5f9b062 100644
--- a/clang/test/CXX/class/class.local/p1-0x.cpp
+++ b/clang/test/CXX/class/class.local/p1-0x.cpp
@@ -11,8 +11,8 @@ void f() {
int x = 3; // expected-note{{'x' declared here}}
struct C {
int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing lambda expression}}
- }c; // expected-note {{required here}}
+ };
};
- C(); // expected-note {{required here}}
+ C();
}
diff --git a/clang/test/CXX/drs/dr26xx.cpp b/clang/test/CXX/drs/dr26xx.cpp
index 36aea39824740..987904913897b 100644
--- a/clang/test/CXX/drs/dr26xx.cpp
+++ b/clang/test/CXX/drs/dr26xx.cpp
@@ -103,19 +103,3 @@ void f() {
brachiosaur |= neck; // OK
}
}
-
-namespace dr2631 { // dr2631: 16
- constexpr int g();
- consteval int f() {
- return g();
- }
- int k(int x = f()) {
- return x;
- }
- constexpr int g() {
- return 42;
- }
- int test() {
- return k();
- }
-}
diff --git a/clang/test/CodeGenCXX/builtin-source-location.cpp b/clang/test/CodeGenCXX/builtin-source-location.cpp
index 7af6749d0d6d6..6e44e6b0e60e3 100644
--- a/clang/test/CodeGenCXX/builtin-source-location.cpp
+++ b/clang/test/CodeGenCXX/builtin-source-location.cpp
@@ -1,6 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers -std=c++2a -fblocks %s -triple x86_64-unknown-unknown -emit-llvm -o %t.ll
-// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -fblocks %s -triple x86_64-unknown-unknown -emit-llvm -o %t.ll
-
// This needs to be performed before #line directives which alter filename
// RUN: %clang_cc1 -no-opaque-pointers -fno-file-reproducible -fmacro-prefix-map=%p=/UNLIKELY/PATH -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-PREFIX-MAP
diff --git a/clang/test/CodeGenCXX/default-arguments-with-immediate.cpp b/clang/test/CodeGenCXX/default-arguments-with-immediate.cpp
deleted file mode 100644
index 54a02ffc06836..0000000000000
--- a/clang/test/CodeGenCXX/default-arguments-with-immediate.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: %clang_cc1 -std=c++2a -triple x86_64-elf-gnu %s -emit-llvm -o - | FileCheck %s
-
-consteval int immediate() { return 0;}
-static int ext();
-void f(int a = immediate() + ext());
-
-void test_function() {
- f();
- f(0);
- // CHECK: call noundef i32 @_ZL3extv()
- // CHECK: add
- // CHECK: call {{.*}} @_Z1fi
- // CHECK: call {{.*}} @_Z1fi
-}
-
-// CHECK: define {{.*}} i32 @_ZL3extv()
-
-static constexpr int not_immediate();
-struct A {
- int a = immediate() + not_immediate();
-};
-
-void test_member() {
- // CHECK: call void @_ZN1AC2Ev
- A defaulted;
- // CHECK-NOT: call void @_ZN1AC2Ev
- A provided{0};
-}
-
-// CHECK: define {{.*}} void @_ZN1AC2Ev{{.*}}
-// CHECK: %call = call noundef i32 @_ZL13not_immediatev()
-
-int never_referenced() {return 42;};
-
-
-namespace not_used {
-
-struct A {
- int a = immediate() + never_referenced();
-};
-void f(int a = immediate() + never_referenced());
-
-void g() {
- A a{0};
- f(0);
-}
-
-}
-
-static int ext() {return 0;}
-static constexpr int not_immediate() {return 0;}
-
-// CHECK-NOT: define {{.*}} i32 _ZL16never_referencedv()(
-// CHECK: define {{.*}} i32 @_ZL13not_immediatev()
diff --git a/clang/test/CodeGenCXX/meminit-initializers-odr.cpp b/clang/test/CodeGenCXX/meminit-initializers-odr.cpp
deleted file mode 100644
index b017159162a86..0000000000000
--- a/clang/test/CodeGenCXX/meminit-initializers-odr.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s
-
-struct ThisShouldBeCalled {
- ThisShouldBeCalled() {}
-};
-
-template <typename T>
-struct ThisShouldBeCalledTPL {
- ThisShouldBeCalledTPL() {}
-};
-
-consteval int f () {
- return 42;
-}
-
-struct WithConsteval {
- WithConsteval(int x = f()) {}
-};
-
-template <typename T>
-struct WithConstevalTPL {
- WithConstevalTPL(T x = f()) {}
-};
-
-
-struct Base {
- ThisShouldBeCalled y = {};
-};
-
-struct S : Base {
- ThisShouldBeCalledTPL<int> A = {};
- WithConsteval B = {};
- WithConstevalTPL<double> C = {};
-};
-void Do(S = S{}) {}
-
-void test() {
- Do();
-}
-
-// CHECK-LABEL: @_ZN18ThisShouldBeCalledC2Ev
-// CHECK-LABEL: @_ZN21ThisShouldBeCalledTPLIiEC2Ev
-// CHECK-LABEL: @_ZN13WithConstevalC2Ei
-// CHECK-LABEL: @_ZN16WithConstevalTPLIdEC2Ed
-
-namespace check_arrays {
-
-template <typename T>
-struct inner {
- inner() {}
-};
-
-struct S {
- inner<int> a {};
-};
-
-class C {
- S s[1]{};
-};
-
-int f() {
- C c;
-}
-
-// CHECK-LABEL: @_ZN12check_arrays5innerIiEC2Ev
-
-}
-
-namespace check_field_inits_in_base_constructors {
-
-template <typename>
-struct ShouldBeODRUsed {
- ShouldBeODRUsed() {}
-};
-class k {
-// The private here is important,
-// otherwise it would be aggregate initialized.
-private:
- ShouldBeODRUsed<k> a = {};
-};
-
-struct b {
- k c{};
-};
-void test() { b d; }
-
-// CHECK-LABEL: @_ZN38check_field_inits_in_base_constructors15ShouldBeODRUsedINS_1kEEC2Ev
-
-}
diff --git a/clang/test/PCH/default-argument-with-immediate-calls.cpp b/clang/test/PCH/default-argument-with-immediate-calls.cpp
deleted file mode 100644
index 510605a23d4e7..0000000000000
--- a/clang/test/PCH/default-argument-with-immediate-calls.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -emit-pch %s -o %t
-// RUN: %clang_cc1 -std=c++20 -include-pch %t -verify %s
-// expected-no-diagnostics
-
-#ifndef HEADER_INCLUDED
-#define HEADER_INCLUDED
-
-consteval int immediate();
-int regular_function() {
- return 0;
-}
-
-struct S {
- int a = immediate() + regular_function();
-};
-
-int f(int arg = immediate()) {
- return arg;
-}
-
-#else
-
-consteval int immediate() {
- return 0;
-}
-
-void test() {
- f(0);
- f();
- S s{0};
- S t{0};
-}
-
-#endif
diff --git a/clang/test/SemaCXX/cxx11-default-member-initializers.cpp b/clang/test/SemaCXX/cxx11-default-member-initializers.cpp
index c24d04a568713..9353e633fafbc 100644
--- a/clang/test/SemaCXX/cxx11-default-member-initializers.cpp
+++ b/clang/test/SemaCXX/cxx11-default-member-initializers.cpp
@@ -1,6 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -verify %s -pedantic
-// RUN: %clang_cc1 -std=c++20 -verify %s -pedantic
-
namespace PR31692 {
struct A {
@@ -14,38 +12,3 @@ namespace PR31692 {
// A::X can now be default-constructed.
static_assert(__is_constructible(A::X), "");
}
-
-
-struct S {
-} constexpr s;
-struct C {
- C(S);
-};
-class MemInit {
- C m = s;
-};
-
-#if __cplusplus >= 202002L
-// This test ensures cleanup expressions are correctly produced
-// in the presence of default member initializers.
-namespace PR136554 {
-struct string {
- constexpr string(const char*) {};
- constexpr ~string();
-};
-struct S;
-struct optional {
- template <typename U = S>
- constexpr optional(U &&) {}
-};
-struct S {
- string a;
- optional b;
- int defaulted = 0;
-} test {
- "", {
- { "", 0 }
- }
-};
-}
-#endif
diff --git a/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp b/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
deleted file mode 100644
index abeb27fd03e35..0000000000000
--- a/clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2b %s
-
-consteval int undefined(); // expected-note 4 {{declared here}}
-
-void check_lambdas_unused(
- int a = []
- {
- // The body of a lambda is not a subexpression of the lambda
- // so this is immediately evaluated even if the parameter
- // is never used.
- return undefined(); // expected-error {{not a constant expression}} \
- // expected-note {{undefined function 'undefined'}}
- }(),
- int b = [](int no_error = undefined()) {
- return no_error;
- }(0),
- int c = [](int defaulted = undefined()) {
- return defaulted;
- }()
-) {}
-
-int check_lambdas_used(
- int b = [](int no_error = undefined()) {
- return no_error;
- }(0),
- int c = [](int defaulted = undefined()) { // expected-error {{not a constant expression}} \
- // expected-note {{declared here}} \
- // expected-note {{undefined function 'undefined'}}
- return defaulted;
- }(), // expected-note {{in the default initalizer of 'defaulted'}}
- int d = [](int defaulted = sizeof(undefined())) {
- return defaulted;
- }()
-) {
- return 0;
-}
-
-int test_check_lambdas_used = check_lambdas_used();
-
-struct UnusedInitWithLambda {
- int a = [] {
- return undefined(); // expected-error {{not a constant expression}} \
- // expected-note {{undefined function 'undefined'}}
- }();
- // UnusedInitWithLambda is never constructed, so the initializer
- // of b and undefined() are never evaluated.
- int b = [](int no_error = undefined()) {
- return no_error;
- }();
-};
-
-consteval int ub(int n) {
- return 0/n; // expected-note {{division}}
-}
-
-struct InitWithLambda {
- int b = [](int error = undefined()) { // expected-error {{not a constant expression}} \
- // expected-note {{declared here}} \
- // expected-note {{undefined function 'undefined'}}
- return error;
- }(); // expected-note {{in the default initalizer of 'error'}}
- int c = [](int error = sizeof(undefined()) + ub(0)) { // expected-error {{'ub' is not a constant expression}} \
- // expected-note {{declared here}} \
- // expected-note {{in call to 'ub(0)}}
- return error;
- }(); // expected-note {{in the default initalizer of 'error'}}
-} i; // expected-note {{in implicit default constructor}}
-
-namespace ShouldNotCrash {
- template<typename T>
- struct F {
- template<typename U>
- F(const U&) {}
- };
- struct A {
- static constexpr auto x = [] {};
- F<int> f = x;
- };
- void f(A a = A()) { }
-}
diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp
index f7c347ce357aa..ccb385f60dc4b 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
-// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -verify %s
// expected-no-diagnostics
#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
@@ -9,22 +8,15 @@
template <unsigned>
struct Printer;
-#ifdef USE_CONSTEVAL
-#define SOURCE_LOC_EVAL_KIND consteval
-#else
-#define SOURCE_LOC_EVAL_KIND constexpr
-#endif
-
namespace std {
class source_location {
struct __impl;
public:
- static SOURCE_LOC_EVAL_KIND source_location
- current(const __impl *__p = __builtin_source_location()) noexcept {
- source_location __loc;
- __loc.__m_impl = __p;
- return __loc;
+ static constexpr source_location current(const __impl *__p = __builtin_source_location()) noexcept {
+ source_location __loc;
+ __loc.__m_impl = __p;
+ return __loc;
}
constexpr source_location() = default;
constexpr source_location(source_location const &) = default;
@@ -601,73 +593,3 @@ namespace TestConstexprContext {
}
static_assert(test());
}
-
-namespace Lambda {
-#line 8000 "TestLambda.cpp"
-constexpr int nested_lambda(int l = []{
- return SL::current().line();
-}()) {
- return l;
-}
-static_assert(nested_lambda() == __LINE__ - 4);
-
-constexpr int lambda_param(int l = [](int l = SL::current().line()) {
- return l;
-}()) {
- return l;
-}
-static_assert(lambda_param() == __LINE__);
-
-
-}
-
-constexpr int compound_literal_fun(int a =
- (int){ SL::current().line() }
-) { return a ;}
-static_assert(compound_literal_fun() == __LINE__);
-
-struct CompoundLiteral {
- int a = (int){ SL::current().line() };
-};
-static_assert(CompoundLiteral{}.a == __LINE__);
-
-
-// FIXME
-// Init captures are subexpressions of the lambda expression
-// so according to the standard immediate invocations in init captures
-// should be evaluated at the call site.
-// However Clang does not yet implement this as it would introduce
-// a fair bit of complexity.
-// We intend to implement that functionality once we find real world
-// use cases that require it.
-constexpr int test_init_capture(int a =
- [b = SL::current().line()] { return b; }()) {
- return a;
-}
-#ifdef USE_CONSTEVAL
-static_assert(test_init_capture() == __LINE__ - 4);
-#else
-static_assert(test_init_capture() == __LINE__ );
-#endif
-
-namespace check_immediate_invocations_in_templates {
-
-template <typename T = int>
-struct G {
- T line = __builtin_LINE();
-};
-template <typename T>
-struct S {
- int i = G<T>{}.line;
-};
-static_assert(S<int>{}.i != // intentional new line
- S<int>{}.i);
-
-template <typename T>
-constexpr int f(int i = G<T>{}.line) {
- return i;
-}
-
-static_assert(f<int>() != // intentional new line
- f<int>());
-}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 9f481cfc43c0d..11c90cc9e940d 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -15593,7 +15593,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://wg21.link/cwg2631">2631</a></td>
<td>DR</td>
<td>Immediate function evaluations in default arguments</td>
- <td class="unreleased" align="center">Clang 16</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2632">
<td><a href="https://wg21.link/cwg2632">2632</a></td>
More information about the cfe-commits
mailing list