yronglin updated this revision to Diff 544386.
yronglin added a comment.
Try implement
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D153701/new/
https://reviews.llvm.org/D153701
Files:
clang/include/clang/AST/ExprCXX.h
clang/include/clang/Sema/Sema.h
clang/lib/CodeGen/CGExpr.cpp
clang/lib/Frontend/FrontendActions.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaStmt.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -410,6 +410,7 @@
case BuildingBuiltinDumpStructCall:
case LambdaExpressionSubstitution:
case BuildingDeductionGuides:
+ case BuiltingCXXForRangeVariable:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -1009,7 +1010,12 @@
<< convertCallArgsToString(
*this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
break;
-
+ case CodeSynthesisContext::BuiltingCXXForRangeVariable:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_building_builtin_dump_struct_call)
+ << convertCallArgsToString(
+ *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
+ break;
case CodeSynthesisContext::Memoization:
break;
@@ -1138,6 +1144,7 @@
case CodeSynthesisContext::MarkingClassDllexported:
case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
case CodeSynthesisContext::BuildingDeductionGuides:
+ case CodeSynthesisContext::BuiltingCXXForRangeVariable:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return std::nullopt;
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2522,6 +2522,12 @@
}
}
+ // Register a note to explain why we're performing the call.
+ CodeSynthesisContext Ctx;
+ Ctx.Kind = CodeSynthesisContext::BuiltingCXXForRangeVariable;
+ Ctx.PointOfInstantiation = ForLoc;
+ pushCodeSynthesisContext(Ctx);
+
// Build auto && __range = range-init
// Divide by 2, since the variables are in the inner scope (loop body).
const auto DepthStr = std::to_string(S->getDepth() / 2);
@@ -2529,8 +2535,10 @@
VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
- if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
- diag::err_for_range_deduction_failure)) {
+ bool Res = FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
+ diag::err_for_range_deduction_failure);
+ popCodeSynthesisContext();
+ if (Res) {
ActOnInitializerError(LoopVar);
return StmtError();
}
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -7355,15 +7355,15 @@
});
}
-static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
- Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits,
- bool EnableLifetimeWarnings);
+static void
+visitLocalsRetainedByInitializer(IndirectLocalPath &Path, Expr *Init,
+ LocalVisitor Visit, bool RevisitSubinits,
+ bool EnableLifetimeWarnings,
+ bool isCXXForRangeVariable = false);
-static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
- Expr *Init, ReferenceKind RK,
- LocalVisitor Visit,
- bool EnableLifetimeWarnings);
+static void visitLocalsRetainedByReferenceBinding(
+ IndirectLocalPath &Path, Expr *Init, ReferenceKind RK, LocalVisitor Visit,
+ bool EnableLifetimeWarnings, bool isCXXForRangeVariable = false);
template <typename T> static bool isRecordWithAttr(QualType Type) {
if (auto *RD = Type->getAsCXXRecordDecl())
@@ -7543,7 +7543,8 @@
}
static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
- LocalVisitor Visit) {
+ LocalVisitor Visit,
+ bool isCXXForRangeVariable = false) {
const FunctionDecl *Callee;
ArrayRef<Expr*> Args;
@@ -7584,7 +7585,8 @@
for (unsigned I = 0,
N = std::min<unsigned>(Callee->getNumParams(), Args.size());
I != N; ++I) {
- if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
+ if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>() ||
+ isCXXForRangeVariable)
VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
}
}
@@ -7594,7 +7596,8 @@
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit,
- bool EnableLifetimeWarnings) {
+ bool EnableLifetimeWarnings,
+ bool isCXXForRangeVariable) {
RevertToOldSizeRAII RAII(Path);
// Walk past any constructs which we can lifetime-extend across.
@@ -7613,7 +7616,15 @@
// Step over any subobject adjustments; we may have a materialized
// temporary inside them.
- Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+ SmallVector<const Expr *, 32> CommaLHS;
+ SmallVector<SubobjectAdjustment, 32> Adjustments;
+ Init = const_cast<Expr *>(
+ Init->skipRValueSubobjectAdjustments(CommaLHS, Adjustments));
+
+ for (auto *LHS : CommaLHS)
+ visitLocalsRetainedByReferenceBinding(Path, const_cast<Expr *>(LHS),
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
// Per current approach for DR1376, look through casts to reference type
// when performing lifetime extension.
@@ -7653,7 +7664,8 @@
if (isa<CallExpr>(Init)) {
if (EnableLifetimeWarnings)
handleGslAnnotatedTypes(Path, Init, Visit);
- return visitLifetimeBoundArguments(Path, Init, Visit);
+ return visitLifetimeBoundArguments(Path, Init, Visit,
+ isCXXForRangeVariable);
}
switch (Init->getStmtClass()) {
@@ -7680,6 +7692,17 @@
break;
}
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(Init);
+ visitLocalsRetainedByReferenceBinding(
+ Path, BO->getLHS(), RK_ReferenceBinding, Visit, EnableLifetimeWarnings,
+ isCXXForRangeVariable);
+ visitLocalsRetainedByReferenceBinding(
+ Path, BO->getRHS(), RK_ReferenceBinding, Visit, EnableLifetimeWarnings,
+ isCXXForRangeVariable);
+ break;
+ }
+
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is Deref. All others don't resolve to a "name." This includes
@@ -7722,7 +7745,8 @@
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
bool RevisitSubinits,
- bool EnableLifetimeWarnings) {
+ bool EnableLifetimeWarnings,
+ bool isCXXForRangeVariable) {
RevertToOldSizeRAII RAII(Path);
Expr *Old;
@@ -8068,6 +8092,10 @@
LifetimeResult LR = getEntityLifetime(&Entity);
LifetimeKind LK = LR.getInt();
const InitializedEntity *ExtendingEntity = LR.getPointer();
+ bool isInitCXXForRangeVarDecl =
+ !CodeSynthesisContexts.empty() &&
+ CodeSynthesisContexts.back().Kind ==
+ CodeSynthesisContext::BuiltingCXXForRangeVariable;
// If this entity doesn't have an interesting lifetime, don't bother looking
// for temporaries within its initializer.
@@ -8081,6 +8109,13 @@
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
+ if (getLangOpts().CPlusPlus23 && MTE && isInitCXXForRangeVarDecl) {
+ MTE->setCanIgnore(false);
+ MTE->setExtendingDecl(ExtendingEntity->getDecl(),
+ ExtendingEntity->allocateManglingNumber());
+ return true;
+ }
+
bool IsGslPtrInitWithGslTempOwner = false;
bool IsLocalGslOwner = false;
if (pathOnlyInitializesGslPointer(Path)) {
@@ -8328,12 +8363,13 @@
diag::warn_dangling_lifetime_pointer, SourceLocation());
llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
if (Init->isGLValue())
- visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
- TemporaryVisitor,
- EnableLifetimeWarnings);
+ visitLocalsRetainedByReferenceBinding(
+ Path, Init, RK_ReferenceBinding, TemporaryVisitor,
+ EnableLifetimeWarnings, isInitCXXForRangeVarDecl);
else
visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false,
- EnableLifetimeWarnings);
+ EnableLifetimeWarnings,
+ isInitCXXForRangeVarDecl);
}
static void DiagnoseNarrowingInInitList(Sema &S,
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8189,16 +8189,17 @@
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
// designated object (and is no longer an lvalue).
- if (E->isPRValue()) {
- // In C, function designators (i.e. expressions of function type)
- // are r-values, but we still want to do function-to-pointer decay
- // on them. This is both technically correct and convenient for
- // some clients.
- if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType())
- return DefaultFunctionArrayConversion(E);
-
- return E;
- }
+ // if ( {
+ // In C, function designators (i.e. expressions of function type)
+ // are r-values, but we still want to do function-to-pointer decay
+ // on them. This is both technically correct and convenient for
+ // some clients.
+ if (E->isPRValue() && !getLangOpts().CPlusPlus &&
+ E->getType()->isFunctionType())
+ return DefaultFunctionArrayConversion(E);
+
+ // return E;
+ // }
if (getLangOpts().CPlusPlus) {
// The C++11 standard defines the notion of a discarded-value expression;
@@ -8225,6 +8226,17 @@
// just clutter.
// FIXME: We don't emit lifetime markers for the temporaries due to this.
// FIXME: Do any other AST consumers care about this?
+
+ // 6.7.7.2.6 - when a prvalue that has type other than cv void appears as
+ // a discarded-value expression ([expr.context]).
+ if (getLangOpts().CPlusPlus17 && E->isPRValue() &&
+ !E->getType()->isVoidType()) {
+ ExprResult Res = TemporaryMaterializationConversion(E);
+ if (Res.isInvalid())
+ return E;
+ E = Res.get();
+ dyn_cast<MaterializeTemporaryExpr>(E)->setCanIgnore();
+ }
return E;
}
Index: clang/lib/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/Frontend/FrontendActions.cpp
+++ clang/lib/Frontend/FrontendActions.cpp
@@ -414,6 +414,8 @@
return "BuildingBuiltinDumpStructCall";
case CodeSynthesisContext::BuildingDeductionGuides:
return "BuildingDeductionGuides";
+ case CodeSynthesisContext::BuiltingCXXForRangeVariable:
+ return "BuiltingCXXForRangeVariable";
}
return "";
}
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -193,6 +193,11 @@
return EmitIgnoredConditionalOperator(CondOp);
}
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ if (MTE->canIgnore())
+ E = MTE->getSubExpr();
+ }
+
// Just emit it as an l-value and drop the result.
EmitLValue(E);
}
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1353,6 +1353,8 @@
bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
+ bool IsCXXForRangeVariable = 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
@@ -9400,6 +9402,9 @@
/// We are building deduction guides for a class.
BuildingDeductionGuides,
+
+ /// We are building an C++ for-range variable.
+ BuiltingCXXForRangeVariable
} Kind;
/// Was the enclosing context a non-instantiation SFINAE context?
Index: clang/include/clang/AST/ExprCXX.h
===================================================================
--- clang/include/clang/AST/ExprCXX.h
+++ clang/include/clang/AST/ExprCXX.h
@@ -4575,6 +4575,7 @@
friend class ASTStmtWriter;
llvm::PointerUnion<Stmt *, LifetimeExtendedTemporaryDecl *> State;
+ bool CanIgnore = false;
public:
MaterializeTemporaryExpr(QualType T, Expr *Temporary,
@@ -4593,6 +4594,10 @@
: State.get<LifetimeExtendedTemporaryDecl *>()->getTemporaryExpr());
}
+ // Wether the MaterializeTemporaryExpr can be ignored.
+ bool canIgnore() const { return CanIgnore; }
+ void setCanIgnore(bool Val = true) { CanIgnore = Val; }
+
/// Retrieve the storage duration for the materialized temporary.
StorageDuration getStorageDuration() const {
return State.is<Stmt *>() ? SD_FullExpression
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits