Fix a couple issues where we didn't correctly delay diagnostics in PotentiallyPotentiallyEvaluated contexts. In preparation for making sizeof() PotentiallyPotentiallyEvaluated.

llvm-svn: 148367
This commit is contained in:
Eli Friedman 2012-01-18 01:05:54 +00:00
parent adcc938c46
commit fbc0dff6f8
5 changed files with 136 additions and 25 deletions

View 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.

View File

@ -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;
}

View 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;
}

View File

@ -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)); }

View File

@ -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'}}