[AST] Add a flag indicating if any subexpression had errors

The only subexpression that is considered an error now is TypoExpr, but
we plan to add expressions with errors to improve editor tooling on broken
code. We intend to use the same mechanism to guard against spurious
diagnostics on those as well.

See the follow-up revision for an actual usage of the flag.

Original patch from Ilya.

Reviewers: sammccall

Reviewed By: sammccall

Tags: #clang

Differential Revision: https://reviews.llvm.org/D65591
This commit is contained in:
Haojian Wu 2020-03-17 10:36:19 +01:00
parent 5d881dd8a8
commit 4b0f1e12c2
12 changed files with 83 additions and 22 deletions

View File

@ -62,6 +62,8 @@ static const TerminalColor LocationColor = {llvm::raw_ostream::YELLOW, false};
static const TerminalColor ValueKindColor = {llvm::raw_ostream::CYAN, false};
// bitfield/objcproperty/objcsubscript/vectorcomponent
static const TerminalColor ObjectKindColor = {llvm::raw_ostream::CYAN, false};
// contains-errors
static const TerminalColor ErrorsColor = {llvm::raw_ostream::RED, true};
// Null statements
static const TerminalColor NullColor = {llvm::raw_ostream::BLUE, false};

View File

@ -59,6 +59,7 @@ class CXXDeleteExpr;
class ArrayTypeTraitExpr;
class ExpressionTraitExpr;
class CXXNoexceptExpr;
class PackExpansionExpr;
class SubstNonTypeTemplateParmExpr;
class CoroutineSuspendExpr;
class DependentCoawaitExpr;
@ -71,6 +72,7 @@ class LambdaExpr;
class CXXUnresolvedConstructExpr;
class CXXDependentScopeMemberExpr;
class MaterializeTemporaryExpr;
class CXXFoldExpr;
class TypeTraitExpr;
class ConceptSpecializationExpr;
class PredefinedExpr;
@ -134,6 +136,7 @@ ExprDependence computeDependence(CXXDeleteExpr *E);
ExprDependence computeDependence(ArrayTypeTraitExpr *E);
ExprDependence computeDependence(ExpressionTraitExpr *E);
ExprDependence computeDependence(CXXNoexceptExpr *E, CanThrowResult CT);
ExprDependence computeDependence(PackExpansionExpr *E);
ExprDependence computeDependence(SubstNonTypeTemplateParmExpr *E);
ExprDependence computeDependence(CoroutineSuspendExpr *E);
ExprDependence computeDependence(DependentCoawaitExpr *E);
@ -149,6 +152,7 @@ ExprDependence computeDependence(LambdaExpr *E,
ExprDependence computeDependence(CXXUnresolvedConstructExpr *E);
ExprDependence computeDependence(CXXDependentScopeMemberExpr *E);
ExprDependence computeDependence(MaterializeTemporaryExpr *E);
ExprDependence computeDependence(CXXFoldExpr *E);
ExprDependence computeDependence(TypeTraitExpr *E);
ExprDependence computeDependence(ConceptSpecializationExpr *E,
bool ValueDependent);

View File

@ -20,19 +20,23 @@ struct ExprDependenceScope {
Type = 4,
Value = 8,
// clang extension: this expr contains or references an error, and is
// considered dependent on how that error is resolved.
Error = 16,
None = 0,
All = 15,
All = 31,
TypeValue = Type | Value,
TypeInstantiation = Type | Instantiation,
ValueInstantiation = Value | Instantiation,
TypeValueInstantiation = Type | Value | Instantiation,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Value)
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error)
};
};
using ExprDependence = ExprDependenceScope::ExprDependence;
static constexpr unsigned ExprDependenceBits = 4;
static constexpr unsigned ExprDependenceBits = 5;
struct TypeDependenceScope {
enum TypeDependence : uint8_t {
@ -47,6 +51,8 @@ struct TypeDependenceScope {
/// Whether this type is a variably-modified type (C99 6.7.5).
VariablyModified = 8,
// FIXME: add Error bit.
None = 0,
All = 15,
@ -83,11 +89,14 @@ LLVM_COMMON_DEPENDENCE(TemplateArgumentDependence)
/// Computes dependencies of a reference with the name having template arguments
/// with \p TA dependencies.
inline ExprDependence toExprDependence(TemplateArgumentDependence TA) {
auto E =
static_cast<ExprDependence>(TA & ~TemplateArgumentDependence::Dependent);
auto D = ExprDependence::None;
if (TA & TemplateArgumentDependence::UnexpandedPack)
D |= ExprDependence::UnexpandedPack;
if (TA & TemplateArgumentDependence::Instantiation)
D |= ExprDependence::Instantiation;
if (TA & TemplateArgumentDependence::Dependent)
return E | ExprDependence::Type | ExprDependence::Value;
return E;
D |= ExprDependence::Type | ExprDependence::Value;
return D;
}
inline ExprDependence toExprDependence(TypeDependence TD) {
// This hack works because TypeDependence and TemplateArgumentDependence
@ -127,10 +136,13 @@ toTemplateArgumentDependence(TemplateNameDependence D) {
}
inline TemplateArgumentDependence
toTemplateArgumentDependence(ExprDependence ED) {
TemplateArgumentDependence TAD = static_cast<TemplateArgumentDependence>(
ED & ~(ExprDependence::Type | ExprDependence::Value));
TemplateArgumentDependence TAD = TemplateArgumentDependence::None;
if (ED & (ExprDependence::Type | ExprDependence::Value))
TAD |= TemplateArgumentDependence::Dependent;
if (ED & ExprDependence::Instantiation)
TAD |= TemplateArgumentDependence::Instantiation;
if (ED & ExprDependence::UnexpandedPack)
TAD |= TemplateArgumentDependence::UnexpandedPack;
return TAD;
}

View File

@ -226,6 +226,12 @@ public:
return static_cast<bool>(getDependence() & ExprDependence::UnexpandedPack);
}
/// Whether this expression contains subexpressions which had errors, e.g. a
/// TypoExpr.
bool containsErrors() const {
return static_cast<bool>(getDependence() & ExprDependence::Error);
}
/// getExprLoc - Return the preferred location for the arrow when diagnosing
/// a problem with a generic expression.
SourceLocation getExprLoc() const LLVM_READONLY;
@ -5881,7 +5887,8 @@ class TypoExpr : public Expr {
public:
TypoExpr(QualType T) : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary) {
assert(T->isDependentType() && "TypoExpr given a non-dependent type");
setDependence(ExprDependence::TypeValueInstantiation);
setDependence(ExprDependence::TypeValueInstantiation |
ExprDependence::Error);
}
child_range children() {

View File

@ -4020,7 +4020,7 @@ public:
EllipsisLoc(EllipsisLoc),
NumExpansions(NumExpansions ? *NumExpansions + 1 : 0),
Pattern(Pattern) {
setDependence(ExprDependence::TypeValueInstantiation);
setDependence(computeDependence(this));
}
PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) {}
@ -4531,7 +4531,7 @@ public:
NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), Opcode(Opcode) {
SubExprs[0] = LHS;
SubExprs[1] = RHS;
setDependence(ExprDependence::TypeValueInstantiation);
setDependence(computeDependence(this));
}
CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {}

View File

@ -1496,7 +1496,7 @@ private:
return CachedLocalOrUnnamed;
}
};
enum { NumTypeBits = 18 };
enum { NumTypeBits = 8 + TypeDependenceBits + 6 };
protected:
// These classes allow subclasses to somewhat cleanly pack bitfields

View File

@ -120,9 +120,9 @@ ExprDependence clang::computeDependence(BinaryConditionalOperator *E) {
}
ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) {
auto D = ExprDependence::None;
if (E->getType()->isDependentType())
D |= ExprDependence::Type;
// FIXME: why is unexpanded-pack not propagated?
auto D = toExprDependence(E->getType()->getDependence()) &
~ExprDependence::UnexpandedPack;
// Note: we treat a statement-expression in a dependent context as always
// being value- and instantiation-dependent. This matches the behavior of
// lambda-expressions and GCC.
@ -172,7 +172,7 @@ ExprDependence clang::computeDependence(VAArgExpr *E) {
ExprDependence clang::computeDependence(NoInitExpr *E) {
return toExprDependence(E->getType()->getDependence()) &
ExprDependence::Instantiation;
(ExprDependence::Instantiation & ExprDependence::Error);
}
ExprDependence clang::computeDependence(ArrayInitLoopExpr *E) {
@ -213,8 +213,8 @@ ExprDependence clang::computeDependence(CXXRewrittenBinaryOperator *E) {
ExprDependence clang::computeDependence(CXXStdInitializerListExpr *E) {
auto D = turnTypeToValueDependence(E->getSubExpr()->getDependence());
if (E->getType()->isDependentType())
D |= ExprDependence::Type;
D |= toExprDependence(E->getType()->getDependence()) &
(ExprDependence::Type | ExprDependence::Error);
return D;
}
@ -296,13 +296,19 @@ ExprDependence clang::computeDependence(CXXNoexceptExpr *E, CanThrowResult CT) {
return D;
}
ExprDependence clang::computeDependence(PackExpansionExpr *E) {
return (E->getPattern()->getDependence() & ~ExprDependence::UnexpandedPack) |
ExprDependence::TypeValueInstantiation;
}
ExprDependence clang::computeDependence(SubstNonTypeTemplateParmExpr *E) {
return E->getReplacement()->getDependence();
}
ExprDependence clang::computeDependence(CoroutineSuspendExpr *E) {
if (auto *Resume = E->getResumeExpr())
return (Resume->getDependence() & ExprDependence::TypeValue) |
return (Resume->getDependence() &
(ExprDependence::TypeValue | ExprDependence::Error)) |
(E->getCommonExpr()->getDependence() & ~ExprDependence::TypeValue);
return E->getCommonExpr()->getDependence() |
ExprDependence::TypeValueInstantiation;
@ -377,6 +383,7 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
if (Decl->isParameterPack())
Deps |= ExprDependence::UnexpandedPack;
Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error;
// (TD) C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
@ -496,6 +503,10 @@ ExprDependence clang::computeDependence(GenericSelectionExpr *E,
bool ContainsUnexpandedPack) {
auto D = ContainsUnexpandedPack ? ExprDependence::UnexpandedPack
: ExprDependence::None;
for (auto *AE : E->getAssocExprs())
D |= AE->getDependence() & ExprDependence::Error;
D |= E->getControllingExpr()->getDependence() & ExprDependence::Error;
if (E->isResultDependent())
return D | ExprDependence::TypeValueInstantiation;
return D | (E->getResultExpr()->getDependence() &
@ -623,7 +634,8 @@ ExprDependence clang::computeDependence(CXXUnresolvedConstructExpr *E) {
if (E->getType()->getContainedDeducedType())
D |= ExprDependence::Type;
for (auto *A : E->arguments())
D |= A->getDependence() & ExprDependence::UnexpandedPack;
D |= A->getDependence() &
(ExprDependence::UnexpandedPack | ExprDependence::Error);
return D;
}
@ -643,6 +655,15 @@ ExprDependence clang::computeDependence(MaterializeTemporaryExpr *E) {
return E->getSubExpr()->getDependence();
}
ExprDependence clang::computeDependence(CXXFoldExpr *E) {
auto D = ExprDependence::TypeValueInstantiation;
for (const auto *C : {E->getLHS(), E->getRHS()}) {
if (C)
D |= C->getDependence() & ~ExprDependence::UnexpandedPack;
}
return D;
}
ExprDependence clang::computeDependence(TypeTraitExpr *E) {
auto D = ExprDependence::None;
for (const auto *A : E->getArgs())

View File

@ -4231,6 +4231,7 @@ DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
ILE->setType(baseExpr->getType());
BaseAndUpdaterExprs[1] = ILE;
// FIXME: this is wrong, set it correctly.
setDependence(ExprDependence::None);
}

View File

@ -126,6 +126,11 @@ void TextNodeDumper::Visit(const Stmt *Node) {
if (const auto *E = dyn_cast<Expr>(Node)) {
dumpType(E->getType());
if (E->containsErrors()) {
ColorScope Color(OS, ShowColors, ErrorsColor);
OS << " contains-errors";
}
{
ColorScope Color(OS, ShowColors, ValueKindColor);
switch (E->getValueKind()) {

View File

@ -106,7 +106,8 @@ namespace clang {
/// The number of record fields required for the Expr class
/// itself.
static const unsigned NumExprFields = NumStmtFields + 7;
static const unsigned NumExprFields =
NumStmtFields + ExprDependenceBits + 3;
/// Read and initialize a ExplicitTemplateArgumentList structure.
void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
@ -517,6 +518,7 @@ void ASTStmtReader::VisitExpr(Expr *E) {
bool ValueDependent = Record.readInt();
bool InstantiationDependent = Record.readInt();
bool ContainsUnexpandedTemplateParameters = Record.readInt();
bool ContainsErrors = Record.readInt();
auto Deps = ExprDependence::None;
if (TypeDependent)
Deps |= ExprDependence::Type;
@ -526,6 +528,8 @@ void ASTStmtReader::VisitExpr(Expr *E) {
Deps |= ExprDependence::Instantiation;
if (ContainsUnexpandedTemplateParameters)
Deps |= ExprDependence::UnexpandedPack;
if (ContainsErrors)
Deps |= ExprDependence::Error;
E->setDependence(Deps);
E->setValueKind(static_cast<ExprValueKind>(Record.readInt()));

View File

@ -2280,6 +2280,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ContainsErrors
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
//DeclRefExpr
@ -2303,6 +2304,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ContainsErrors
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
//Integer Literal
@ -2321,6 +2323,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ContainsErrors
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
//Character Literal
@ -2339,6 +2342,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ContainsErrors
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
// CastExpr

View File

@ -540,6 +540,7 @@ void ASTStmtWriter::VisitExpr(Expr *E) {
Record.push_back(E->isValueDependent());
Record.push_back(E->isInstantiationDependent());
Record.push_back(E->containsUnexpandedParameterPack());
Record.push_back(E->containsErrors());
Record.push_back(E->getValueKind());
Record.push_back(E->getObjectKind());
}