forked from OSchip/llvm-project
PR52537: When performing a no-op TreeTransform of a rewritten binary
operator, mark any functions it calls as referenced.
This commit is contained in:
parent
062ef8f6b4
commit
4a9523c55f
|
@ -5114,7 +5114,8 @@ public:
|
||||||
/// type -- entities referenced by the type are now referenced.
|
/// type -- entities referenced by the type are now referenced.
|
||||||
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
|
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
|
||||||
void MarkDeclarationsReferencedInExpr(Expr *E,
|
void MarkDeclarationsReferencedInExpr(Expr *E,
|
||||||
bool SkipLocalVariables = false);
|
bool SkipLocalVariables = false,
|
||||||
|
ArrayRef<const Expr *> StopAt = None);
|
||||||
|
|
||||||
/// Try to recover by turning the given expression into a
|
/// Try to recover by turning the given expression into a
|
||||||
/// call. Returns true if recovery was attempted or an error was
|
/// call. Returns true if recovery was attempted or an error was
|
||||||
|
|
|
@ -18867,14 +18867,22 @@ class EvaluatedExprMarker : public UsedDeclVisitor<EvaluatedExprMarker> {
|
||||||
public:
|
public:
|
||||||
typedef UsedDeclVisitor<EvaluatedExprMarker> Inherited;
|
typedef UsedDeclVisitor<EvaluatedExprMarker> Inherited;
|
||||||
bool SkipLocalVariables;
|
bool SkipLocalVariables;
|
||||||
|
ArrayRef<const Expr *> StopAt;
|
||||||
|
|
||||||
EvaluatedExprMarker(Sema &S, bool SkipLocalVariables)
|
EvaluatedExprMarker(Sema &S, bool SkipLocalVariables,
|
||||||
: Inherited(S), SkipLocalVariables(SkipLocalVariables) {}
|
ArrayRef<const Expr *> StopAt)
|
||||||
|
: Inherited(S), SkipLocalVariables(SkipLocalVariables), StopAt(StopAt) {}
|
||||||
|
|
||||||
void visitUsedDecl(SourceLocation Loc, Decl *D) {
|
void visitUsedDecl(SourceLocation Loc, Decl *D) {
|
||||||
S.MarkFunctionReferenced(Loc, cast<FunctionDecl>(D));
|
S.MarkFunctionReferenced(Loc, cast<FunctionDecl>(D));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Visit(Expr *E) {
|
||||||
|
if (std::find(StopAt.begin(), StopAt.end(), E) != StopAt.end())
|
||||||
|
return;
|
||||||
|
Inherited::Visit(E);
|
||||||
|
}
|
||||||
|
|
||||||
void VisitDeclRefExpr(DeclRefExpr *E) {
|
void VisitDeclRefExpr(DeclRefExpr *E) {
|
||||||
// If we were asked not to visit local variables, don't.
|
// If we were asked not to visit local variables, don't.
|
||||||
if (SkipLocalVariables) {
|
if (SkipLocalVariables) {
|
||||||
|
@ -18901,9 +18909,11 @@ public:
|
||||||
///
|
///
|
||||||
/// \param SkipLocalVariables If true, don't mark local variables as
|
/// \param SkipLocalVariables If true, don't mark local variables as
|
||||||
/// 'referenced'.
|
/// 'referenced'.
|
||||||
|
/// \param StopAt Subexpressions that we shouldn't recurse into.
|
||||||
void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
|
void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
|
||||||
bool SkipLocalVariables) {
|
bool SkipLocalVariables,
|
||||||
EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E);
|
ArrayRef<const Expr*> StopAt) {
|
||||||
|
EvaluatedExprMarker(*this, SkipLocalVariables, StopAt).Visit(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a diagnostic when statements are reachable.
|
/// Emit a diagnostic when statements are reachable.
|
||||||
|
|
|
@ -11008,14 +11008,10 @@ ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator(
|
||||||
if (RHS.isInvalid())
|
if (RHS.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if (!getDerived().AlwaysRebuild() &&
|
|
||||||
LHS.get() == Decomp.LHS &&
|
|
||||||
RHS.get() == Decomp.RHS)
|
|
||||||
return E;
|
|
||||||
|
|
||||||
// Extract the already-resolved callee declarations so that we can restrict
|
// Extract the already-resolved callee declarations so that we can restrict
|
||||||
// ourselves to using them as the unqualified lookup results when rebuilding.
|
// ourselves to using them as the unqualified lookup results when rebuilding.
|
||||||
UnresolvedSet<2> UnqualLookups;
|
UnresolvedSet<2> UnqualLookups;
|
||||||
|
bool ChangedAnyLookups = false;
|
||||||
Expr *PossibleBinOps[] = {E->getSemanticForm(),
|
Expr *PossibleBinOps[] = {E->getSemanticForm(),
|
||||||
const_cast<Expr *>(Decomp.InnerBinOp)};
|
const_cast<Expr *>(Decomp.InnerBinOp)};
|
||||||
for (Expr *PossibleBinOp : PossibleBinOps) {
|
for (Expr *PossibleBinOp : PossibleBinOps) {
|
||||||
|
@ -11032,9 +11028,23 @@ ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator(
|
||||||
E->getOperatorLoc(), Callee->getFoundDecl()));
|
E->getOperatorLoc(), Callee->getFoundDecl()));
|
||||||
if (!Found)
|
if (!Found)
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
if (Found != Callee->getFoundDecl())
|
||||||
|
ChangedAnyLookups = true;
|
||||||
UnqualLookups.addDecl(Found);
|
UnqualLookups.addDecl(Found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!getDerived().AlwaysRebuild() && !ChangedAnyLookups &&
|
||||||
|
LHS.get() == Decomp.LHS && RHS.get() == Decomp.RHS) {
|
||||||
|
// Mark all functions used in the rewrite as referenced. Note that when
|
||||||
|
// a < b is rewritten to (a <=> b) < 0, both the <=> and the < might be
|
||||||
|
// function calls, and/or there might be a user-defined conversion sequence
|
||||||
|
// applied to the operands of the <.
|
||||||
|
// FIXME: this is a bit instantiation-specific.
|
||||||
|
const Expr *StopAt[] = {Decomp.LHS, Decomp.RHS};
|
||||||
|
SemaRef.MarkDeclarationsReferencedInExpr(E, false, StopAt);
|
||||||
|
return E;
|
||||||
|
}
|
||||||
|
|
||||||
return getDerived().RebuildCXXRewrittenBinaryOperator(
|
return getDerived().RebuildCXXRewrittenBinaryOperator(
|
||||||
E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get());
|
E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,3 +425,39 @@ namespace PR44992 {
|
||||||
friend auto operator<=>(s const &, s const &) = default;
|
friend auto operator<=>(s const &, s const &) = default;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PR52537 {
|
||||||
|
template<typename T> struct X {};
|
||||||
|
template<typename T> bool operator==(const X<T> &, int) { return T::error; } // expected-error 2{{no members}}
|
||||||
|
template<typename T> int operator<=>(const X<T> &, int) { return T::error; } // expected-error 2{{no members}}
|
||||||
|
|
||||||
|
const X<int[1]> x1;
|
||||||
|
template<typename T> bool f1() { return x1 != 0; } // expected-note {{instantiation of}}
|
||||||
|
void g1() { f1<int>(); } // expected-note {{instantiation of}}
|
||||||
|
|
||||||
|
const X<int[2]> x2;
|
||||||
|
template<typename T> bool f2() { return 0 == x2; } // expected-note {{instantiation of}}
|
||||||
|
void g2() { f2<int>(); } // expected-note {{instantiation of}}
|
||||||
|
|
||||||
|
const X<int[3]> x3;
|
||||||
|
template<typename T> bool f3() { return x3 < 0; } // expected-note {{instantiation of}}
|
||||||
|
void g3() { f3<int>(); } // expected-note {{instantiation of}}
|
||||||
|
|
||||||
|
const X<int[4]> x4;
|
||||||
|
template<typename T> bool f4() { return 0 >= x4; } // expected-note {{instantiation of}}
|
||||||
|
void g4() { f4<int>(); } // expected-note {{instantiation of}}
|
||||||
|
|
||||||
|
template<typename T> struct Y {};
|
||||||
|
template<typename T> struct Z { Z(int) { T::error; } using nondeduced = Z; }; // expected-error 2{{no members}}
|
||||||
|
template<typename T> Z<T> operator<=>(const Y<T>&, int);
|
||||||
|
template<typename T> bool operator<(const Z<T>&, const typename Z<T>::nondeduced&);
|
||||||
|
template<typename T> bool operator<(const typename Z<T>::nondeduced&, const Z<T>&);
|
||||||
|
|
||||||
|
const Y<int[5]> y5;
|
||||||
|
template<typename T> bool f5() { return y5 < 0; } // expected-note {{instantiation of}}
|
||||||
|
void g5() { f5<int>(); } // expected-note {{instantiation of}}
|
||||||
|
|
||||||
|
const Y<int[6]> y6;
|
||||||
|
template<typename T> bool f6() { return 0 < y6; } // expected-note {{instantiation of}}
|
||||||
|
void g6() { f6<int>(); } // expected-note {{instantiation of}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue