[clang] 4b0f1e1 - [AST] Add a flag indicating if any subexpression had errors

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 19 00:58:57 PDT 2020


Author: Haojian Wu
Date: 2020-03-19T08:56:10+01:00
New Revision: 4b0f1e12c243dd4c42665df0e2eab61f2fc4d237

URL: https://github.com/llvm/llvm-project/commit/4b0f1e12c243dd4c42665df0e2eab61f2fc4d237
DIFF: https://github.com/llvm/llvm-project/commit/4b0f1e12c243dd4c42665df0e2eab61f2fc4d237.diff

LOG: [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

Added: 
    

Modified: 
    clang/include/clang/AST/ASTDumperUtils.h
    clang/include/clang/AST/ComputeDependence.h
    clang/include/clang/AST/DependenceFlags.h
    clang/include/clang/AST/Expr.h
    clang/include/clang/AST/ExprCXX.h
    clang/include/clang/AST/Type.h
    clang/lib/AST/ComputeDependence.cpp
    clang/lib/AST/Expr.cpp
    clang/lib/AST/TextNodeDumper.cpp
    clang/lib/Serialization/ASTReaderStmt.cpp
    clang/lib/Serialization/ASTWriterDecl.cpp
    clang/lib/Serialization/ASTWriterStmt.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/ASTDumperUtils.h b/clang/include/clang/AST/ASTDumperUtils.h
index 55a085449a9b..1dce913049ad 100644
--- a/clang/include/clang/AST/ASTDumperUtils.h
+++ b/clang/include/clang/AST/ASTDumperUtils.h
@@ -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};

diff  --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index 593ff3a6eb16..69ccb6c676e5 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -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);

diff  --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h
index 21daf0a203ac..ee6439fc984c 100644
--- a/clang/include/clang/AST/DependenceFlags.h
+++ b/clang/include/clang/AST/DependenceFlags.h
@@ -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;
 }
 

diff  --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 7448281c9289..0a136a737658 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -226,6 +226,12 @@ class Expr : public ValueStmt {
     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() {

diff  --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 33ea3f6346b2..e3404fec02dd 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4020,7 +4020,7 @@ class PackExpansionExpr : public Expr {
         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 @@ class CXXFoldExpr : public Expr {
         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) {}

diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index e72b44fbb31f..05c6167dcbb2 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1496,7 +1496,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
       return CachedLocalOrUnnamed;
     }
   };
-  enum { NumTypeBits = 18 };
+  enum { NumTypeBits = 8 + TypeDependenceBits + 6 };
 
 protected:
   // These classes allow subclasses to somewhat cleanly pack bitfields

diff  --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 4ca4eacde8b7..348fae1cfb19 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -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())

diff  --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 6591b0481d4b..9b0cc2b69dd4 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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);
 }
 

diff  --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 0b86dbb87347..6a6d8692228a 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -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()) {

diff  --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index d74b0d514eda..1fbcab209303 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -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()));

diff  --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f7d89299e140..0fc90f5d835b 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -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

diff  --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 588977525b65..b25b2df8783a 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -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());
 }


        


More information about the cfe-commits mailing list