From: Eli Friedman Date: Wed, 18 Jan 2012 01:05:54 +0000 (+0000) Subject: Fix a couple issues where we didn't correctly delay diagnostics in PotentiallyPotenti... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93c878ee093f2a233c32b29f074e6a3f511e333f;p=clang Fix a couple issues where we didn't correctly delay diagnostics in PotentiallyPotentiallyEvaluated contexts. In preparation for making sizeof() PotentiallyPotentiallyEvaluated. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148367 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d9aece0c8b..482f12c719 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -165,6 +165,7 @@ namespace sema { class DelayedDiagnostic; class FunctionScopeInfo; class LambdaScopeInfo; + class PossiblyUnreachableDiag; class TemplateDeductionInfo; } @@ -519,6 +520,12 @@ public: typedef SmallVector, 10> PotentiallyEmittedDiagnostics; + typedef SmallVector + PotentiallyEmittedDelayedDiag; + + typedef SmallVector + 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. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 33c8a83b40..3eda420940 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #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; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 0d30749266..f3582975ec 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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 index 0000000000..0e8451b472 --- /dev/null +++ b/test/SemaCXX/runtimediag-ppe.cpp @@ -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 index 0000000000..c9ff81110d --- /dev/null +++ b/test/SemaObjCXX/arc-ppe.mm @@ -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'}}