]> granicus.if.org Git - clang/commitdiff
Fix a couple issues where we didn't correctly delay diagnostics in PotentiallyPotenti...
authorEli Friedman <eli.friedman@gmail.com>
Wed, 18 Jan 2012 01:05:54 +0000 (01:05 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 18 Jan 2012 01:05:54 +0000 (01:05 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148367 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaType.cpp
test/SemaCXX/runtimediag-ppe.cpp [new file with mode: 0644]
test/SemaObjCXX/arc-ppe.mm [new file with mode: 0644]

index d9aece0c8b74099434325b1e67639518e7e4dd9c..482f12c719680154e8d0d10953e65e749b02ff34 100644 (file)
@@ -165,6 +165,7 @@ namespace sema {
   class DelayedDiagnostic;
   class FunctionScopeInfo;
   class LambdaScopeInfo;
+  class PossiblyUnreachableDiag;
   class TemplateDeductionInfo;
 }
 
@@ -519,6 +520,12 @@ public:
   typedef SmallVector<std::pair<SourceLocation, PartialDiagnostic>, 10>
     PotentiallyEmittedDiagnostics;
 
+  typedef SmallVector<sema::DelayedDiagnostic, 10>
+    PotentiallyEmittedDelayedDiag;
+
+  typedef SmallVector<sema::PossiblyUnreachableDiag, 10>
+    PotentiallyEmittedPossiblyUnreachableDiag;
+
   /// \brief Describes how the expressions currently being parsed are
   /// evaluated at run-time, if at all.
   enum ExpressionEvaluationContext {
@@ -579,16 +586,20 @@ public:
     /// evaluated.
     PotentiallyReferencedDecls *PotentiallyReferenced;
 
-    /// \brief The set of diagnostics to emit should this potentially
-    /// potentially-evaluated context become evaluated.
-    PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
+    // There are three kinds of diagnostics we care about in
+    // PotentiallyPotentiallyEvaluated contexts: regular Diag diagnostics,
+    // DelayedDiagnostics, and DiagRuntimeBehavior diagnostics.  
+    PotentiallyEmittedDiagnostics *SavedDiag;
+    PotentiallyEmittedDelayedDiag *SavedDelayedDiag;
+    PotentiallyEmittedPossiblyUnreachableDiag *SavedRuntimeDiag;
 
     ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
                                       unsigned NumCleanupObjects,
                                       bool ParentNeedsCleanups)
       : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
         NumCleanupObjects(NumCleanupObjects),
-        PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
+        PotentiallyReferenced(0), SavedDiag(0), SavedDelayedDiag(0), 
+        SavedRuntimeDiag(0) { }
 
     void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
       if (!PotentiallyReferenced)
@@ -596,18 +607,13 @@ public:
       PotentiallyReferenced->push_back(std::make_pair(Loc, Decl));
     }
 
-    void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) {
-      if (!PotentiallyDiagnosed)
-        PotentiallyDiagnosed = new PotentiallyEmittedDiagnostics;
-      PotentiallyDiagnosed->push_back(std::make_pair(Loc, PD));
-    }
+    void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD);
 
-    void Destroy() {
-      delete PotentiallyReferenced;
-      delete PotentiallyDiagnosed;
-      PotentiallyReferenced = 0;
-      PotentiallyDiagnosed = 0;
-    }
+    void addRuntimeDiagnostic(const sema::PossiblyUnreachableDiag &PUD);
+
+    void addDelayedDiagnostic(const sema::DelayedDiagnostic &DD);
+
+    void Destroy();
   };
 
   /// A stack of expression evaluation contexts.
index 33c8a83b40f5b4d4e7d2c3d32fc0a17f6604f723..3eda4209402a7a46d2f0ffc06a0e404cd80618a1 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/DelayedDiagnostic.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/AnalysisBasedWarnings.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTMutationListener.h"
@@ -9360,6 +9362,39 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result,
   return false;
 }
 
+void Sema::ExpressionEvaluationContextRecord::Destroy() {
+  delete PotentiallyReferenced;
+  delete SavedDiag;
+  delete SavedRuntimeDiag;
+  delete SavedDelayedDiag;
+  PotentiallyReferenced = 0;
+  SavedDiag = 0;
+  SavedRuntimeDiag = 0;
+  SavedDelayedDiag = 0;
+}
+
+void Sema::ExpressionEvaluationContextRecord::addDiagnostic(
+        SourceLocation Loc, const PartialDiagnostic &PD) {
+  if (!SavedDiag)
+    SavedDiag = new PotentiallyEmittedDiagnostics;
+  SavedDiag->push_back(std::make_pair(Loc, PD));
+}
+
+void Sema::ExpressionEvaluationContextRecord::addRuntimeDiagnostic(
+        const sema::PossiblyUnreachableDiag &PUD) {
+  if (!SavedRuntimeDiag)
+    SavedRuntimeDiag = new PotentiallyEmittedPossiblyUnreachableDiag;
+  SavedRuntimeDiag->push_back(PUD);
+}
+
+void Sema::ExpressionEvaluationContextRecord::addDelayedDiagnostic(
+        const sema::DelayedDiagnostic &DD) {
+  if (!SavedDelayedDiag)
+    SavedDelayedDiag = new PotentiallyEmittedDelayedDiag;
+  SavedDelayedDiag->push_back(DD);
+}
+
+
 void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
   ExprEvalContexts.push_back(
@@ -9386,14 +9421,32 @@ void Sema::PopExpressionEvaluationContext() {
         MarkDeclarationReferenced(I->first, I->second);
     }
 
-    if (Rec.PotentiallyDiagnosed) {
+    if (Rec.SavedDiag) {
       // Emit any pending diagnostics.
       for (PotentiallyEmittedDiagnostics::iterator
-                I = Rec.PotentiallyDiagnosed->begin(),
-             IEnd = Rec.PotentiallyDiagnosed->end();
+                I = Rec.SavedDiag->begin(),
+             IEnd = Rec.SavedDiag->end();
            I != IEnd; ++I)
         Diag(I->first, I->second);
     }
+
+    if (Rec.SavedDelayedDiag) {
+      // Emit any pending delayed diagnostics.
+      for (PotentiallyEmittedDelayedDiag::iterator
+                I = Rec.SavedDelayedDiag->begin(),
+             IEnd = Rec.SavedDelayedDiag->end();
+           I != IEnd; ++I)
+        DelayedDiagnostics.add(*I);
+    }
+
+    if (Rec.SavedRuntimeDiag) {
+      // Emit any pending runtime diagnostics.
+      for (PotentiallyEmittedPossiblyUnreachableDiag::iterator
+                I = Rec.SavedRuntimeDiag->begin(),
+             IEnd = Rec.SavedRuntimeDiag->end();
+           I != IEnd; ++I)
+             FunctionScopes.back()->PossiblyUnreachableDiags.push_back(*I);
+    }
   }
 
   // When are coming out of an unevaluated context, clear out any
@@ -9759,7 +9812,8 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
     return true;
 
   case PotentiallyPotentiallyEvaluated:
-    ExprEvalContexts.back().addDiagnostic(Loc, PD);
+    ExprEvalContexts.back().addRuntimeDiagnostic(
+        sema::PossiblyUnreachableDiag(PD, Loc, Statement));
     break;
   }
 
index 0d30749266775561172892610702dbfeec2f9da6..f3582975ecdba6f980e2855ca6f86bd3d33cf7c2 100644 (file)
@@ -1057,23 +1057,40 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
   } else if (type->isObjCARCImplicitlyUnretainedType()) {
     implicitLifetime = Qualifiers::OCL_ExplicitNone;
 
-  // If we are in an unevaluated context, like sizeof, assume ExplicitNone and
+  // If we are in an unevaluated context, like sizeof, assume Autoreleasing and
   // don't give error.
   } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated ||
              S.ExprEvalContexts.back().Context == Sema::ConstantEvaluated) {
-    implicitLifetime = Qualifiers::OCL_ExplicitNone;
+    implicitLifetime = Qualifiers::OCL_Autoreleasing;
 
   // If that failed, give an error and recover using __autoreleasing.
   } else {
     // These types can show up in private ivars in system headers, so
     // we need this to not be an error in those cases.  Instead we
     // want to delay.
+    //
+    // Also, make sure we delay appropriately in
+    // PotentiallyPotentiallyEvaluated contexts.
     if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
-      S.DelayedDiagnostics.add(
-          sema::DelayedDiagnostic::makeForbiddenType(loc,
-              diag::err_arc_indirect_no_ownership, type, isReference));
+      if (S.ExprEvalContexts.back().Context ==
+          Sema::PotentiallyPotentiallyEvaluated) {
+        S.ExprEvalContexts.back().addDelayedDiagnostic(
+            sema::DelayedDiagnostic::makeForbiddenType(loc,
+                diag::err_arc_indirect_no_ownership, type, isReference));
+      } else {
+        S.DelayedDiagnostics.add(
+            sema::DelayedDiagnostic::makeForbiddenType(loc,
+                diag::err_arc_indirect_no_ownership, type, isReference));
+      }
     } else {
-      S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference;
+      if (S.ExprEvalContexts.back().Context ==
+          Sema::PotentiallyPotentiallyEvaluated) {
+        S.ExprEvalContexts.back().addDiagnostic(loc,
+            S.PDiag(diag::err_arc_indirect_no_ownership)
+                << type << isReference);
+      } else {
+        S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference;
+      }
     }
     implicitLifetime = Qualifiers::OCL_Autoreleasing;
   }
diff --git a/test/SemaCXX/runtimediag-ppe.cpp b/test/SemaCXX/runtimediag-ppe.cpp
new file mode 100644 (file)
index 0000000..0e8451b
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Make sure diagnostics that we don't print based on runtime control
+// flow are delayed correctly in cases where we can't immediately tell whether
+// the context is unevaluated.
+
+namespace std {
+  class type_info;
+}
+
+int& NP(int);
+void test1() { (void)typeid(NP(1 << 32)); }
+
+class Poly { virtual ~Poly(); };
+Poly& P(int);
+void test2() { (void)typeid(P(1 << 32)); } // expected-warning {{shift count >= width of type}}
+
+void test3() { 1 ? (void)0 : (void)typeid(P(1 << 32)); }
diff --git a/test/SemaObjCXX/arc-ppe.mm b/test/SemaObjCXX/arc-ppe.mm
new file mode 100644 (file)
index 0000000..c9ff811
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-arc %s
+
+// Make sure the ARC auto-deduction of id* in unevaluated contexts
+// works correctly in cases where we can't immediately tell whether the
+// context is unevaluated.
+
+namespace std {
+  class type_info;
+}
+
+int& NP(void*);
+void test1() { (void)typeid(NP((void*)(id*)0)); }
+
+class Poly { virtual ~Poly(); };
+Poly& P(void*);
+void test2() { (void)typeid(P((void*)(id*)0)); } // expected-error {{pointer to non-const type 'id'}}