cor3ntin created this revision.
Herald added a subscriber: martong.
Herald added a reviewer: shafik.
Herald added a project: All.
cor3ntin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D136554
Files:
clang/include/clang/AST/ExprCXX.h
clang/include/clang/AST/Stmt.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/ExprCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1748,6 +1748,9 @@
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;
}
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1828,6 +1828,9 @@
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) {
@@ -3821,7 +3824,7 @@
break;
case EXPR_CXX_DEFAULT_ARG:
- S = new (Context) CXXDefaultArgExpr(Empty);
+ S = CXXDefaultArgExpr::CreateEmpty(Context, /*HasRewrittenInit*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_DEFAULT_INIT:
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -3164,8 +3164,8 @@
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide different behavior.
- ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) {
- return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param,
+ ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param, Expr* RewrittenExpr) {
+ return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param, RewrittenExpr,
getSema().CurContext);
}
@@ -12052,11 +12052,18 @@
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)
+ E->getUsedContext() == SemaRef.CurContext && InitRes.get() == E->getRewrittenExpr())
return E;
- return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
+ return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param, InitRes.get());
}
template<typename Derived>
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1928,8 +1928,7 @@
getDescribedFunctionTemplate() &&
"Default arg expressions are never formed in dependent cases.");
return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(),
- cast<FunctionDecl>(E->getParam()->getDeclContext()),
- E->getParam());
+ cast<FunctionDecl>(E->getParam()->getDeclContext()), E->getParam());
}
template<typename Fn>
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -5856,8 +5856,9 @@
}
bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param) {
+ ParmVarDecl *Param, Expr* Init) {
if (Param->hasUnparsedDefaultArg()) {
+ assert(!Init && "Should not have an 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)) {
@@ -5874,11 +5875,16 @@
return true;
}
- if (Param->hasUninstantiatedDefaultArg() &&
- InstantiateDefaultArgument(CallLoc, FD, Param))
- return true;
+ if (Param->hasUninstantiatedDefaultArg()) {
+ assert(!Init && "Should not have an init expression yet");
+ if(InstantiateDefaultArgument(CallLoc, FD, Param))
+ return true;
+ }
+ if(!Init) {
+ Init = Param->getInit();
+ }
- assert(Param->hasInit() && "default argument but no initializer?");
+ assert(Init && "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
@@ -5887,34 +5893,73 @@
// 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 Init = dyn_cast<ExprWithCleanups>(Param->getInit())) {
+ if (auto InitWithCleanup = dyn_cast<ExprWithCleanups>(Init)) {
// Set the "needs cleanups" bit regardless of whether there are
// any explicit objects.
- Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects());
-
+ Cleanup.setExprNeedsCleanups(InitWithCleanup->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(!Init->getNumObjects() &&
+ assert(!InitWithCleanup->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".
+ /// Do not try to check immediate invocations when checking defaults arguments
+ llvm::SaveAndRestore<bool> DisableIITracking(
+ CheckingDefaultArgument, true);
+
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
- MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
- /*SkipLocalVariables=*/true);
+ MarkDeclarationsReferencedInExpr(Init, true);
return false;
}
+
+struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> {
+ bool HasImmediateCalls = false;
+ bool VisitCallExpr(CallExpr *E) {
+ if(const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(E->getCalleeDecl())) {
+ HasImmediateCalls = HasImmediateCalls || FD->isConsteval();
+ }
+ return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
+ }
+
+ bool VisitSourceLocExpr(SourceLocExpr *E) {
+ HasImmediateCalls = true;
+ return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
+ }
+};
+
+struct EnsureImmediateInvocationInDefaultArgs : TreeTransform<EnsureImmediateInvocationInDefaultArgs> {
+ EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef) : TreeTransform(SemaRef) {}
+};
+
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
- FunctionDecl *FD, ParmVarDecl *Param) {
+ FunctionDecl *FD, ParmVarDecl *Param, Expr* Init) {
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
- if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
+
+ if(!Init && !Param->hasUnparsedDefaultArg() && !Param->hasUninstantiatedDefaultArg()) {
+ ImmediateCallVisitor V;
+ V.TraverseDecl(Param);
+ if(V.HasImmediateCalls) {
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Param);
+ EnsureImmediateInvocationInDefaultArgs Immediate(*this);
+ llvm::SaveAndRestore<bool> RebuildRAII(RebuildingDefaultArgument, true);
+ ExprResult Res = Immediate.TransformExpr(Param->getInit());
+ if(Res.isInvalid())
+ return ExprError();
+ Res = ConvertParamDefaultArgument(Param, Res.get(), Res.get()->getBeginLoc());
+ if(Res.isInvalid())
+ return ExprError();
+ Init = Res.get();
+ }
+ }
+ llvm::SaveAndRestore<bool> DisableIITracking(CheckingDefaultArgument, true);
+ if (CheckCXXDefaultArgExpr(CallLoc, FD, Param, Init))
return ExprError();
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
+
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param, Init, CurContext);
}
Sema::VariadicCallType
@@ -17538,7 +17583,7 @@
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
- !Decl->isConsteval() || isConstantEvaluated() ||
+ !Decl->isConsteval() || isConstantEvaluated() || isDefaultArgumentContext() ||
RebuildingImmediateInvocation || isImmediateFunctionContext())
return E;
@@ -17691,7 +17736,7 @@
/// When we have more then 1 ImmediateInvocationCandidates we need to check
/// for nested ImmediateInvocationCandidates. when we have only 1 we only
/// need to remove ReferenceToConsteval in the immediate invocation.
- if (Rec.ImmediateInvocationCandidates.size() > 1) {
+ if (Rec.ImmediateInvocationCandidates.size() > 1) {
/// Prevent sema calls during the tree transform from adding pointers that
/// are already in the sets.
@@ -17722,10 +17767,10 @@
if (!CE.getInt())
EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
for (auto *DR : Rec.ReferenceToConsteval) {
- auto *FD = cast<FunctionDecl>(DR->getDecl());
- SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
- << FD;
- SemaRef.Diag(FD->getLocation(), diag::note_declared_at);
+ auto *FD = cast<FunctionDecl>(DR->getDecl());
+ SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
+ << FD;
+ SemaRef.Diag(FD->getLocation(), diag::note_declared_at);
}
}
@@ -18818,11 +18863,13 @@
}
}
-
// If the variable is declared in the current context, there is no need to
// capture it.
if (VarDC == DC) return true;
+ if(RebuildingDefaultArgument)
+ return true;
+
// Capture global variables if it is required to use private copy of this
// variable.
bool IsGlobal = !VD->hasLocalStorage();
@@ -19731,7 +19778,7 @@
if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
if (!isUnevaluatedContext() && !isConstantEvaluated() &&
- !isImmediateFunctionContext() && FD->isConsteval() &&
+ !isImmediateFunctionContext() && !isDefaultArgumentContext() && FD->isConsteval() &&
!RebuildingImmediateInvocation && !FD->isDependentContext())
ExprEvalContexts.back().ReferenceToConsteval.insert(E);
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
Index: clang/lib/AST/ExprCXX.cpp
===================================================================
--- clang/lib/AST/ExprCXX.cpp
+++ clang/lib/AST/ExprCXX.cpp
@@ -949,6 +949,52 @@
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 ? 1 : 0);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, RewrittenExpr,
+ UsedContext);
+}
+
+const Expr *CXXDefaultArgExpr::getExpr() const {
+ return CXXDefaultArgExprBits.HasRewrittenInit? getAdjustedRewrittenExpr() : getParam()->getDefaultArg();
+}
+
+Expr *CXXDefaultArgExpr::getExpr() {
+ return CXXDefaultArgExprBits.HasRewrittenInit? getAdjustedRewrittenExpr() : getParam()->getDefaultArg();
+}
+
+const Expr *CXXDefaultArgExpr::getAdjustedRewrittenExpr() const {
+ if(!hasRewrittenInit())
+ return nullptr;
+ const Expr* Init = getRewrittenExpr();
+
+ if (auto *E = dyn_cast_or_null<FullExpr>(Init))
+ if (!isa<ConstantExpr>(E))
+ return E->getSubExpr();
+ return Init;
+}
+
+Expr *CXXDefaultArgExpr::getAdjustedRewrittenExpr() {
+ if(!hasRewrittenInit())
+ return nullptr;
+ Expr* Init = getRewrittenExpr();
+ if (auto *E = dyn_cast_or_null<FullExpr>(Init))
+ if (!isa<ConstantExpr>(E))
+ return E->getSubExpr();
+ return Init;
+}
+
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
SourceLocation Loc, FieldDecl *Field,
QualType Ty, DeclContext *UsedContext)
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -7691,9 +7691,15 @@
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, *UsedContextOrErr);
+ *ToParamOrErr, RewrittenInit, *UsedContextOrErr);
}
ExpectedStmt
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1037,6 +1037,14 @@
/// functions aren't tracked when this is set.
bool RebuildingImmediateInvocation = false;
+ /// Whether we are currently checking a default argument
+ /// This disables immediate invocation checking
+ bool CheckingDefaultArgument = false;
+
+ /// Whether we are currently rebuilding a default argument
+ /// This disable capture check in lambdas
+ bool RebuildingDefaultArgument = false;
+
/// Used to change context to isConstantEvaluated without pushing a heavy
/// ExpressionEvaluationContextRecord object.
bool isConstantEvaluatedOverride;
@@ -6201,13 +6209,13 @@
/// Instantiate or parse a C++ default argument expression as necessary.
/// Return true on error.
bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param);
+ ParmVarDecl *Param, Expr *Init = nullptr);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD,
- ParmVarDecl *Param);
+ ParmVarDecl *Param, Expr *Init = nullptr);
/// FinalizeVarWithDestructor - Prepare for calling destructor on the
/// constructed variable.
@@ -9573,6 +9581,20 @@
return ExprEvalContexts.back().isImmediateFunctionContext();
}
+ bool isDefaultArgumentContext() const {
+ if(CheckingDefaultArgument)
+ return true;
+ assert(!ExprEvalContexts.empty() &&
+ "Must be in an expression evaluation context");
+ for(const ExpressionEvaluationContextRecord & Ctx : llvm::reverse(ExprEvalContexts)) {
+ if(Ctx.Context == ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed)
+ return true;
+ if(Ctx.isUnevaluated())
+ return false;
+ }
+ return false;
+ }
+
/// RAII class used to determine whether SFINAE has
/// trapped any errors that occur during template argument
/// deduction.
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -686,6 +686,10 @@
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;
};
Index: clang/include/clang/AST/ExprCXX.h
===================================================================
--- clang/include/clang/AST/ExprCXX.h
+++ clang/include/clang/AST/ExprCXX.h
@@ -1245,8 +1245,12 @@
/// 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 {
+class CXXDefaultArgExpr final
+ : public Expr
+ , private llvm::TrailingObjects<CXXDefaultArgExpr, Expr *> {
friend class ASTStmtReader;
+ friend class ASTReader;
+ friend TrailingObjects;
/// The parameter whose default is being used.
ParmVarDecl *Param;
@@ -1254,7 +1258,9 @@
/// The context where the default argument expression was used.
DeclContext *UsedContext;
- CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *Param,
+ CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc,
+ ParmVarDecl *Param,
+ Expr* InitExpr,
DeclContext *UsedContext)
: Expr(SC,
Param->hasUnparsedDefaultArg()
@@ -1262,30 +1268,52 @@
: Param->getDefaultArg()->getType(),
Param->getDefaultArg()->getValueKind(),
Param->getDefaultArg()->getObjectKind()),
- Param(Param), UsedContext(UsedContext) {
+ Param(Param),
+ UsedContext(UsedContext) {
CXXDefaultArgExprBits.Loc = Loc;
+ CXXDefaultArgExprBits.HasRewrittenInit = InitExpr != nullptr;
+ if (InitExpr)
+ *getTrailingObjects<Expr *>() = InitExpr;
setDependence(computeDependence(this));
}
+ CXXDefaultArgExpr(EmptyShell Empty, bool HasRewrittenInit)
+ : Expr(CXXDefaultArgExprClass, Empty) {
+ CXXDefaultArgExprBits.HasRewrittenInit = HasRewrittenInit;
+ }
+
+ size_t numTrailingObjects() const {
+ return CXXDefaultArgExprBits.HasRewrittenInit;
+ }
+
public:
- CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
+ static CXXDefaultArgExpr *CreateEmpty(const ASTContext &C, bool HasRewrittenInit);
// \p Param is the parameter whose default argument is used by this
// expression.
static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
ParmVarDecl *Param,
- DeclContext *UsedContext) {
- return new (C)
- CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, UsedContext);
- }
-
+ Expr* RewrittenExpr,
+ DeclContext *UsedContext);
// Retrieve the parameter that the argument was created from.
const ParmVarDecl *getParam() const { return Param; }
ParmVarDecl *getParam() { return Param; }
- // Retrieve the actual argument to the function call.
- const Expr *getExpr() const { return getParam()->getDefaultArg(); }
- Expr *getExpr() { return getParam()->getDefaultArg(); }
+ bool hasRewrittenInit() const { return CXXDefaultArgExprBits.HasRewrittenInit; }
+
+ // Retrieve the argument to the function call.
+ const Expr *getExpr() const;
+ Expr *getExpr();
+
+ const Expr *getRewrittenExpr() const {
+ return hasRewrittenInit() ? *getTrailingObjects<Expr *>() : nullptr;
+ }
+ Expr *getRewrittenExpr() {
+ return hasRewrittenInit() ? *getTrailingObjects<Expr *>() : nullptr;
+ }
+
+ const Expr *getAdjustedRewrittenExpr() const;
+ Expr *getAdjustedRewrittenExpr();
const DeclContext *getUsedContext() const { return UsedContext; }
DeclContext *getUsedContext() { return UsedContext; }
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits