ilya-biryukov created this revision.
Herald added a subscriber: martong.
Herald added a reviewer: shafik.
Herald added a project: All.
ilya-biryukov requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
They must be evaluated in the context where default argument is actually
used during a call, not in a parameter list where default argument is specified.
Fixes #56379.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D132941
Files:
clang/include/clang/AST/CurrentSourceLocExprScope.h
clang/include/clang/AST/Expr.h
clang/include/clang/AST/ExprCXX.h
clang/include/clang/AST/Stmt.h
clang/include/clang/AST/TextNodeDumper.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Expr.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/CodeGenCXX/builtin-source-location.cpp
clang/test/SemaCXX/source_location.cpp
clang/test/SemaCXX/source_location_consteval.cpp
Index: clang/test/SemaCXX/source_location_consteval.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/source_location_consteval.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+namespace std {
+class source_location {
+ struct __impl;
+
+public:
+ static consteval 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;
+ constexpr unsigned int line() const noexcept { return __m_impl ? __m_impl->_M_line : 0; }
+ constexpr unsigned int column() const noexcept { return __m_impl ? __m_impl->_M_column : 0; }
+ constexpr const char *file() const noexcept { return __m_impl ? __m_impl->_M_file_name : ""; }
+ constexpr const char *function() const noexcept { return __m_impl ? __m_impl->_M_function_name : ""; }
+
+private:
+ // Note: The type name "std::source_location::__impl", and its constituent
+ // field-names are required by __builtin_source_location().
+ struct __impl {
+ const char *_M_file_name;
+ const char *_M_function_name;
+ unsigned _M_line;
+ unsigned _M_column;
+ };
+ const __impl *__m_impl = nullptr;
+
+public:
+ using public_impl_alias = __impl;
+};
+} // namespace std
+
+using SL = std::source_location;
+
+constexpr bool is_equal(const char *LHS, const char *RHS) {
+ while (*LHS != 0 && *RHS != 0) {
+ if (*LHS != *RHS)
+ return false;
+ ++LHS;
+ ++RHS;
+ }
+ return *LHS == 0 && *RHS == 0;
+}
+
+constexpr SL get_sl(SL l = SL::current()) { return l; }
+SL get_sl_not_const(SL l = SL::current()) { return l; }
+
+#line 700 "CheckDefaultArg.h"
+constexpr SL l = get_sl();
+static_assert(l.line() == 700);
+static_assert(is_equal(l.file(), "CheckDefaultArg.h"));
+
+int test() {
+ static_assert(is_equal(get_sl().function(), __PRETTY_FUNCTION__));
+ static_assert(get_sl().line() == __LINE__);
+ return get_sl().line() + get_sl_not_const().line();
+}
Index: clang/test/SemaCXX/source_location.cpp
===================================================================
--- clang/test/SemaCXX/source_location.cpp
+++ clang/test/SemaCXX/source_location.cpp
@@ -364,8 +364,8 @@
template <class T>
void func_template_tests() {
constexpr auto P = test_func_template(42);
- //static_assert(is_equal(P.first.function(), __func__), "");
- //static_assert(!is_equal(P.second.function(), __func__), "");
+ static_assert(is_equal(P.first.function(), __PRETTY_FUNCTION__), "");
+ static_assert(!is_equal(P.second.function(), __PRETTY_FUNCTION__), "");
}
template void func_template_tests<int>();
Index: clang/test/CodeGenCXX/builtin-source-location.cpp
===================================================================
--- clang/test/CodeGenCXX/builtin-source-location.cpp
+++ clang/test/CodeGenCXX/builtin-source-location.cpp
@@ -13,12 +13,12 @@
namespace std {
class source_location {
public:
- static constexpr source_location current(const void *__p = __builtin_source_location()) noexcept {
+ static consteval source_location current(const void *__p = __builtin_source_location()) noexcept {
source_location __loc;
__loc.__m_impl = static_cast<const __impl *>(__p);
return __loc;
}
- static source_location bad_current(const void *__p = __builtin_source_location()) noexcept {
+ static constexpr source_location bad_current(const void *__p = __builtin_source_location()) noexcept {
return current(__p);
}
constexpr source_location() = default;
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1747,6 +1747,9 @@
Record.AddDeclRef(E->getParam());
Record.AddDeclRef(cast_or_null<Decl>(E->getUsedContext()));
Record.AddSourceLocation(E->getUsedLocation());
+ Record.push_back(E->hasRewrittenArg());
+ if (E->hasRewrittenArg())
+ Record.AddStmt(E->getExpr());
Code = serialization::EXPR_CXX_DEFAULT_ARG;
}
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1827,6 +1827,9 @@
E->Param = readDeclAs<ParmVarDecl>();
E->UsedContext = readDeclAs<DeclContext>();
E->CXXDefaultArgExprBits.Loc = readSourceLocation();
+ E->CXXDefaultArgExprBits.HasRewrittenArg = Record.readInt();
+ if (E->CXXDefaultArgExprBits.HasRewrittenArg)
+ *E->getTrailingObjects<Expr *>() = Record.readSubExpr();
}
void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
@@ -3817,7 +3820,9 @@
break;
case EXPR_CXX_DEFAULT_ARG:
- S = new (Context) CXXDefaultArgExpr(Empty);
+ S = CXXDefaultArgExpr::CreateEmpty(
+ Context,
+ /*HasRewrittenArg*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_DEFAULT_INIT:
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -847,8 +847,9 @@
if (!Attr)
return;
for (unsigned I = 0; I != NumParams; ++I) {
+ Expr *Dummy;
(void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor,
- Ctor->getParamDecl(I));
+ Ctor->getParamDecl(I), Dummy);
CleanupVarDeclMarking();
}
}
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -1051,7 +1051,8 @@
// We don't keep the instantiated default argument expressions around so
// we must rebuild them here.
for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) {
- if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)))
+ Expr* Dummy;
+ if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I), Dummy))
return true;
}
}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17,6 +17,9 @@
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CurrentSourceLocExprScope.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
@@ -44,9 +47,11 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
+#include "clang/Sema/Ownership.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
@@ -5848,8 +5853,30 @@
ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc);
}
+static bool IsStdSourceLocationCurrent(Decl* D) {
+ auto *F = D ? dyn_cast<FunctionDecl>(D) : nullptr;
+ auto *FuncName = F ? F->getIdentifier() : nullptr;
+ if (!FuncName || !FuncName->isStr("current") || !F->isConsteval())
+ return false;
+ auto *Cls = dyn_cast<RecordDecl>(F->getDeclContext());
+ auto *ClsName = Cls ? Cls->getIdentifier() : nullptr;
+ return ClsName && ClsName->isStr("source_location") && Cls->isInStdNamespace();
+}
+
+static bool IsCallToStdSourceLocationCurrent(Expr* E) {
+ CallExpr *Call = dyn_cast<CallExpr>(E);
+ auto *Callee = Call ? Call->getCalleeDecl() : nullptr;
+ return Callee && IsStdSourceLocationCurrent(Callee);
+}
+
+static ExprResult EvaluateSourceLocations(Sema &S, ParmVarDecl *Param,
+ SourceLocation CallLoc,
+ DeclContext *UsedContext);
+
bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param) {
+ ParmVarDecl *Param, Expr *&RewrittenArg) {
+ RewrittenArg = nullptr;
+
if (Param->hasUnparsedDefaultArg()) {
// If we've already cleared out the location for the default argument,
// that means we're parsing it right now.
@@ -5873,6 +5900,12 @@
assert(Param->hasInit() && "default argument but no initializer?");
+ ExprResult NewArg = EvaluateSourceLocations(*this, Param, CallLoc, CurContext);
+ if (NewArg.isInvalid())
+ return true;
+ if (NewArg.get() != Param->getDefaultArg())
+ RewrittenArg = NewArg.get();
+
// If the default expression creates temporaries, we need to
// push them to the current stack of expression temporaries so they'll
// be properly destroyed.
@@ -5905,9 +5938,11 @@
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD, ParmVarDecl *Param) {
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
- if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
+ Expr* RewrittenArg = nullptr;
+ if (CheckCXXDefaultArgExpr(CallLoc, FD, Param, RewrittenArg))
return ExprError();
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext,
+ RewrittenArg);
}
Sema::VariadicCallType
@@ -17519,13 +17554,20 @@
}
static void EvaluateAndDiagnoseImmediateInvocation(
- Sema &SemaRef, Sema::ImmediateInvocationCandidate Candidate) {
+ Sema &SemaRef, Sema::ImmediateInvocationCandidate Candidate, bool InDefaultArg) {
llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
Expr::EvalResult Eval;
Eval.Diag = &Notes;
ConstantExpr *CE = Candidate.getPointer();
+ // [support.srcloc.cons]p2.
+ // Any call to current that appears as a default argument ([dcl.fct.default]),
+ // or as a subexpression thereof, should correspond to the location of the
+ // invocation of the function that uses the default argument ([expr.call]).
+ if (InDefaultArg && IsCallToStdSourceLocationCurrent(CE->getSubExpr()))
+ return; // Postpone evaluation until we see the context.
bool Result = CE->EvaluateAsConstantExpr(
- Eval, SemaRef.getASTContext(), ConstantExprKind::ImmediateInvocation);
+ Eval, SemaRef.getASTContext(), ConstantExprKind::ImmediateInvocation,
+ SemaRef.OverridenSourceLocs);
if (!Result || !Notes.empty()) {
Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit();
if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr))
@@ -17546,6 +17588,51 @@
CE->MoveIntoResult(Eval.Val, SemaRef.getASTContext());
}
+static ExprResult EvaluateSourceLocations(Sema &S, ParmVarDecl* Param,
+ SourceLocation CallLoc,
+ DeclContext *UsedContext) {
+ struct Transform : TreeTransform<Transform> {
+ using TreeTransform::TreeTransform;
+
+ bool AlwaysRebuild() { return OverrideAlwaysRebuild; }
+
+ ExprResult TransformCallExpr(CallExpr* Call) {
+ if (!IsCallToStdSourceLocationCurrent(Call))
+ return TreeTransform::TransformCallExpr(Call);
+ // Rebuild the call so it gets to the list of immedicate invocations.
+ llvm::SaveAndRestore<bool> Guard(OverrideAlwaysRebuild, true);
+ return TreeTransform::TransformCallExpr(Call);
+ }
+
+ private:
+ bool OverrideAlwaysRebuild = false;
+ };
+ // Force evaluation of calls to source_location::current().
+ // TODO(HACK): potentially evaluated is clearly wrong in some cases?
+ CurrentSourceLocExprScope Locs;
+ CurrentSourceLocExprScope::SourceLocExprScopeGuard LG(
+ SourceLocExpr::Context{CallLoc, UsedContext}, Locs);
+ llvm::SaveAndRestore<CurrentSourceLocExprScope *> SwapLocs(
+ S.OverridenSourceLocs, &Locs);
+
+ EnterExpressionEvaluationContext Eval(
+ S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
+ Sema::ReuseLambdaContextDecl_t{});
+ ExprResult NewArg = Transform(S).TransformExpr(Param->getDefaultArg());
+ if (NewArg.isUsable() && NewArg.get() != Param->getDefaultArg()) {
+ NewArg = S.ConvertParamDefaultArgument(Param, NewArg.get(),
+ NewArg.get()->getBeginLoc());
+ }
+ if (NewArg.isInvalid())
+ return NewArg;
+ // Mimic the logic of ParmVarDecl::getDefaultArg().
+ if (auto *E = dyn_cast_or_null<FullExpr>(NewArg.get())) {
+ if (!isa<ConstantExpr>(E))
+ return E->getSubExpr();
+ }
+ return NewArg;
+}
+
static void RemoveNestedImmediateInvocation(
Sema &SemaRef, Sema::ExpressionEvaluationContextRecord &Rec,
SmallVector<Sema::ImmediateInvocationCandidate, 4>::reverse_iterator It) {
@@ -17664,7 +17751,8 @@
}
for (auto CE : Rec.ImmediateInvocationCandidates)
if (!CE.getInt())
- EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
+ EvaluateAndDiagnoseImmediateInvocation(
+ SemaRef, CE, /*InDefaultArg=*/Rec.isPotentiallyEvaluatedIfUsed());
for (auto DR : Rec.ReferenceToConsteval) {
auto *FD = cast<FunctionDecl>(DR->getDecl());
SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -6142,7 +6142,8 @@
// that we can properly codegen the constructor closure.
if (!Class->isDependentContext()) {
for (ParmVarDecl *PD : CD->parameters()) {
- (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), CD, PD);
+ Expr* Dummy;
+ (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), CD, PD, Dummy);
S.DiscardCleanupsInEvaluationContext();
}
}
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -23,6 +23,7 @@
#include "VarBypassDetector.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
@@ -1622,7 +1623,8 @@
CXXDefaultInitExprScope(CodeGenFunction &CGF, const CXXDefaultInitExpr *E)
: CGF(CGF), OldCXXThisValue(CGF.CXXThisValue),
OldCXXThisAlignment(CGF.CXXThisAlignment),
- SourceLocScope(E, CGF.CurSourceLocExprScope) {
+ SourceLocScope(SourceLocExpr::Context::FromDefaultInit(E),
+ CGF.CurSourceLocExprScope) {
CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getPointer();
CGF.CXXThisAlignment = CGF.CXXDefaultInitExprThis.getAlignment();
}
@@ -1640,7 +1642,8 @@
struct CXXDefaultArgExprScope : SourceLocExprScopeGuard {
CXXDefaultArgExprScope(CodeGenFunction &CGF, const CXXDefaultArgExpr *E)
- : SourceLocExprScopeGuard(E, CGF.CurSourceLocExprScope) {}
+ : SourceLocExprScopeGuard(SourceLocExpr::Context::FromDefaultArg(E),
+ CGF.CurSourceLocExprScope) {}
};
/// The scope of an ArrayInitLoopExpr. Within this scope, the value of the
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -646,7 +646,7 @@
Value *VisitSourceLocExpr(SourceLocExpr *SLE) {
auto &Ctx = CGF.getContext();
APValue Evaluated =
- SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getDefaultExpr());
+ SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getSLocs());
return ConstantEmitter(CGF).emitAbstract(SLE->getLocation(), Evaluated,
SLE->getType());
}
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/LocInfoType.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Module.h"
@@ -999,6 +1000,10 @@
[=] { Visit(Node->getAPValueResult(), Node->getType()); });
}
+void TextNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr* Node) {
+ AddChild("expr", [=] { Node->getExpr()->dumpColor(); });
+}
+
void TextNodeDumper::VisitCallExpr(const CallExpr *Node) {
if (Node->usesADL())
OS << " adl";
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -7448,7 +7448,8 @@
{ return StmtVisitorTy::Visit(E->getReplacement()); }
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
TempVersionRAII RAII(*Info.CurrentCall);
- SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
+ SourceLocExprScopeGuard Guard(SourceLocExpr::Context::FromDefaultArg(E),
+ Info.CurrentCall->CurSourceLocExprScope);
return StmtVisitorTy::Visit(E->getExpr());
}
bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
@@ -7456,7 +7457,8 @@
// The initializer may not have been parsed yet, or might be erroneous.
if (!E->getExpr())
return Error(E);
- SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
+ SourceLocExprScopeGuard Guard(SourceLocExpr::Context::FromDefaultInit(E),
+ Info.CurrentCall->CurSourceLocExprScope);
return StmtVisitorTy::Visit(E->getExpr());
}
@@ -8771,7 +8773,7 @@
bool VisitSourceLocExpr(const SourceLocExpr *E) {
assert(!E->isIntType() && "SourceLocExpr isn't a pointer type?");
APValue LValResult = E->EvaluateInContext(
- Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
+ Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getSLocs());
Result.setFrom(Info.Ctx, LValResult);
return true;
}
@@ -11122,7 +11124,7 @@
bool IntExprEvaluator::VisitSourceLocExpr(const SourceLocExpr *E) {
APValue Evaluated = E->EvaluateInContext(
- Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
+ Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getSLocs());
return Success(Evaluated, E);
}
@@ -15146,14 +15148,18 @@
return true;
}
-bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
- ConstantExprKind Kind) const {
+bool Expr::EvaluateAsConstantExpr(
+ EvalResult &Result, const ASTContext &Ctx, ConstantExprKind Kind,
+ CurrentSourceLocExprScope *SLocs) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
+ if (SLocs) {
+ Info.BottomFrame.CurSourceLocExprScope = *SLocs;
+ }
// The type of the object we're initializing is 'const T' for a class NTTP.
QualType T = getType();
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -2168,20 +2168,27 @@
llvm_unreachable("unexpected IdentKind!");
}
+SourceLocExpr::Context
+SourceLocExpr::Context::FromDefaultArg(const CXXDefaultArgExpr *E) {
+ return {E->getUsedLocation(), E->getUsedContext()};
+}
+
+SourceLocExpr::Context
+SourceLocExpr::Context::FromDefaultInit(const CXXDefaultInitExpr *E) {
+ return {E->getUsedLocation(), E->getUsedContext()};
+}
+
APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
- const Expr *DefaultExpr) const {
+ llvm::Optional<Context> LocCtx) const {
SourceLocation Loc;
const DeclContext *Context;
-
- std::tie(Loc,
- Context) = [&]() -> std::pair<SourceLocation, const DeclContext *> {
- if (auto *DIE = dyn_cast_or_null<CXXDefaultInitExpr>(DefaultExpr))
- return {DIE->getUsedLocation(), DIE->getUsedContext()};
- if (auto *DAE = dyn_cast_or_null<CXXDefaultArgExpr>(DefaultExpr))
- return {DAE->getUsedLocation(), DAE->getUsedContext()};
- return {this->getLocation(), this->getParentContext()};
- }();
-
+ if (LocCtx) {
+ Loc = LocCtx->UsedLocation;
+ Context = LocCtx->UsedContext;
+ } else {
+ Loc = this->getLocation();
+ Context = this->getParentContext();
+ }
PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(
Ctx.getSourceManager().getExpansionRange(Loc).getEnd());
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -7661,8 +7661,16 @@
return std::move(Err);
}
+ Expr* RewrittenArg = nullptr;
+ if (E->hasRewrittenArg()) {
+ auto ArgOrErr = import(E->getExpr());
+ if (!ArgOrErr) return ArgOrErr.takeError();
+ RewrittenArg = *ArgOrErr;
+ }
+
return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
- *ToParamOrErr, *UsedContextOrErr);
+ *ToParamOrErr, *UsedContextOrErr,
+ RewrittenArg);
}
ExpectedStmt
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -19,6 +19,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Availability.h"
#include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/CurrentSourceLocExprScope.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
@@ -1360,10 +1361,16 @@
ExpressionEvaluationContext::ImmediateFunctionContext &&
InDiscardedStatement);
}
+
+ bool isPotentiallyEvaluatedIfUsed() const {
+ return Context == ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed;
+ }
};
/// A stack of expression evaluation contexts.
SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
+ /// Used to evaluate source locations.
+ CurrentSourceLocExprScope* OverridenSourceLocs = nullptr;
/// Emit a warning for all pending noderef expressions that we recorded.
void WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec);
@@ -6126,7 +6133,7 @@
/// 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 *&RewrittenArg);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
@@ -9436,6 +9443,12 @@
return ExprEvalContexts.back().isImmediateFunctionContext();
}
+ bool isPotentiallyEvaluatedIfUsedContext() const {
+ assert(!ExprEvalContexts.empty() &&
+ "Must be in an expression evaluation context");
+ return ExprEvalContexts.back().isPotentiallyEvaluatedIfUsed();
+ }
+
/// RAII class used to determine whether SFINAE has
/// trapped any errors that occur during template argument
/// deduction.
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -248,6 +248,7 @@
void VisitCaseStmt(const CaseStmt *Node);
void VisitCompoundStmt(const CompoundStmt *Node);
void VisitConstantExpr(const ConstantExpr *Node);
+ void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
void VisitCallExpr(const CallExpr *Node);
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node);
void VisitCastExpr(const CastExpr *Node);
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -686,6 +686,9 @@
unsigned : NumExprBits;
+ /// Whether this CXXDefaultArgExpr rewrote its argument and stores a copy.
+ unsigned HasRewrittenArg : 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
@@ -1238,8 +1238,11 @@
/// 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 TrailingObjects;
/// The parameter whose default is being used.
ParmVarDecl *Param;
@@ -1247,8 +1250,13 @@
/// The context where the default argument expression was used.
DeclContext *UsedContext;
+ CXXDefaultArgExpr(EmptyShell Empty, bool HasRewrittenArg)
+ : Expr(CXXDefaultArgExprClass, Empty) {
+ CXXDefaultArgExprBits.HasRewrittenArg = HasRewrittenArg;
+ }
+
CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *Param,
- DeclContext *UsedContext)
+ DeclContext *UsedContext, Expr* RewrittenArg)
: Expr(SC,
Param->hasUnparsedDefaultArg()
? Param->getType().getNonReferenceType()
@@ -1256,29 +1264,54 @@
Param->getDefaultArg()->getValueKind(),
Param->getDefaultArg()->getObjectKind()),
Param(Param), UsedContext(UsedContext) {
+ CXXDefaultArgExprBits.HasRewrittenArg = !!RewrittenArg;
CXXDefaultArgExprBits.Loc = Loc;
+ if (RewrittenArg)
+ *getTrailingObjects<Expr *>() = RewrittenArg;
setDependence(computeDependence(this));
}
+ size_t numTrailingObjects() const {
+ return CXXDefaultArgExprBits.HasRewrittenArg;
+ }
+
public:
- CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
+
+ static CXXDefaultArgExpr *CreateEmpty(const ASTContext &C, bool HasRewrittenArg) {
+ size_t Size = totalSizeToAlloc<Expr*>(HasRewrittenArg);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(EmptyShell(), HasRewrittenArg);
+ }
// \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);
+ DeclContext *UsedContext,
+ Expr* RewrittenArg = nullptr) {
+ size_t Size = totalSizeToAlloc<Expr*>(RewrittenArg != nullptr);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
+ UsedContext, RewrittenArg);
}
+ bool hasRewrittenArg() const { return CXXDefaultArgExprBits.HasRewrittenArg; }
+
// 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(); }
+ const Expr *getExpr() const {
+ if (CXXDefaultArgExprBits.HasRewrittenArg)
+ return *getTrailingObjects<Expr *>();
+ return getParam()->getDefaultArg();
+ }
+ Expr *getExpr() {
+ if (CXXDefaultArgExprBits.HasRewrittenArg)
+ return *getTrailingObjects<Expr *>();
+ return getParam()->getDefaultArg();
+ }
const DeclContext *getUsedContext() const { return UsedContext; }
DeclContext *getUsedContext() { return UsedContext; }
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -18,6 +18,7 @@
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclAccessPair.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
@@ -55,6 +56,7 @@
class StringLiteral;
class TargetInfo;
class ValueDecl;
+ class CurrentSourceLocExprScope;
/// A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
@@ -732,9 +734,9 @@
/// Evaluate an expression that is required to be a constant expression. Does
/// not check the syntactic constraints for C and C++98 constant expressions.
- bool EvaluateAsConstantExpr(
- EvalResult &Result, const ASTContext &Ctx,
- ConstantExprKind Kind = ConstantExprKind::Normal) const;
+ bool EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
+ ConstantExprKind Kind = ConstantExprKind::Normal,
+ CurrentSourceLocExprScope *SLocs = nullptr) const;
/// If the current Expr is a pointer, this will try to statically
/// determine the number of bytes available where the pointer is pointing.
@@ -4689,10 +4691,18 @@
/// Build an empty call expression.
explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
+ struct Context {
+ SourceLocation UsedLocation;
+ const DeclContext *UsedContext = nullptr;
+
+ static Context FromDefaultArg(const CXXDefaultArgExpr* E);
+ static Context FromDefaultInit(const CXXDefaultInitExpr* E);
+ };
+
/// Return the result of evaluating this SourceLocExpr in the specified
/// (and possibly null) default argument or initialization context.
APValue EvaluateInContext(const ASTContext &Ctx,
- const Expr *DefaultExpr) const;
+ llvm::Optional<Context> LocCtx) const;
/// Return a string representing the name of the specific builtin function.
StringRef getBuiltinStr() const;
Index: clang/include/clang/AST/CurrentSourceLocExprScope.h
===================================================================
--- clang/include/clang/AST/CurrentSourceLocExprScope.h
+++ clang/include/clang/AST/CurrentSourceLocExprScope.h
@@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_AST_CURRENTSOURCELOCEXPRSCOPE_H
#define LLVM_CLANG_AST_CURRENTSOURCELOCEXPRSCOPE_H
+#include "clang/AST/Expr.h"
+#include "llvm/ADT/Optional.h"
#include <cassert>
namespace clang {
@@ -23,8 +25,9 @@
/// value of the source location builtins (ex. __builtin_LINE), including the
/// context of default argument and default initializer expressions.
class CurrentSourceLocExprScope {
- /// The CXXDefaultArgExpr or CXXDefaultInitExpr we're currently evaluating.
- const Expr *DefaultExpr = nullptr;
+ /// The source locations coming from CXXDefaultArgExpr or CXXDefaultInitExpr
+ /// we're currently evaluating.
+ llvm::Optional<SourceLocExpr::Context> Context;
public:
/// A RAII style scope guard used for tracking the current source
@@ -32,27 +35,23 @@
/// (ex. __builtin_LINE).
class SourceLocExprScopeGuard;
- const Expr *getDefaultExpr() const { return DefaultExpr; }
+ llvm::Optional<SourceLocExpr::Context> getSLocs() const { return Context; }
explicit CurrentSourceLocExprScope() = default;
private:
- explicit CurrentSourceLocExprScope(const Expr *DefaultExpr)
- : DefaultExpr(DefaultExpr) {}
-
- CurrentSourceLocExprScope(CurrentSourceLocExprScope const &) = default;
- CurrentSourceLocExprScope &
- operator=(CurrentSourceLocExprScope const &) = default;
+ explicit CurrentSourceLocExprScope(
+ llvm::Optional<SourceLocExpr::Context> Context)
+ : Context(std::move(Context)) {}
};
class CurrentSourceLocExprScope::SourceLocExprScopeGuard {
public:
- SourceLocExprScopeGuard(const Expr *DefaultExpr,
+ SourceLocExprScopeGuard(SourceLocExpr::Context Context,
CurrentSourceLocExprScope &Current)
: Current(Current), OldVal(Current), Enable(false) {
- assert(DefaultExpr && "the new scope should not be empty");
- if ((Enable = (Current.getDefaultExpr() == nullptr)))
- Current = CurrentSourceLocExprScope(DefaultExpr);
+ if ((Enable = (!Current.getSLocs().has_value())))
+ Current = CurrentSourceLocExprScope(Context);
}
~SourceLocExprScopeGuard() {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits