diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-12-12 07:57:52 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-12-12 07:57:52 +0000 |
commit | 06d33699f11277a494c1118a0d25a83dab3bbd4c (patch) | |
tree | 61713de316eceb857586102887dd1930308fae8e | |
parent | a63d40f85c4621f5ad2362e0d00879933625404b (diff) |
When certain diagnostics involving run-time behavior would be emitted
in a potentially potentially evaluated context, queue those
diagnostics and only emit them if the context ends up being
potentially evaluated. This completes the fix for PR5761.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91213 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/Sema.h | 18 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 43 | ||||
-rw-r--r-- | test/SemaCXX/vararg-non-pod.cpp | 13 |
3 files changed, 60 insertions, 14 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index baf9c23da5..ada8aa157a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -339,6 +339,10 @@ public: typedef std::vector<std::pair<SourceLocation, Decl *> > PotentiallyReferencedDecls; + /// \brief A set of diagnostics that may be emitted. + typedef std::vector<std::pair<SourceLocation, PartialDiagnostic> > + PotentiallyEmittedDiagnostics; + /// \brief Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { @@ -358,10 +362,14 @@ public: /// evaluated. PotentiallyReferencedDecls *PotentiallyReferenced; + /// \brief The set of diagnostics to emit should this potentially + /// potentially-evaluated context become evaluated. + PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumTemporaries) : Context(Context), NumTemporaries(NumTemporaries), - PotentiallyReferenced(0) { } + PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } void addReferencedDecl(SourceLocation Loc, Decl *Decl) { if (!PotentiallyReferenced) @@ -369,9 +377,17 @@ 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 Destroy() { delete PotentiallyReferenced; + delete PotentiallyDiagnosed; PotentiallyReferenced = 0; + PotentiallyDiagnosed = 0; } }; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1ca47a40aa..7cdc275c7e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -271,7 +271,9 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { return true; case PotentiallyPotentiallyEvaluated: - // FIXME: queue it! + ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), + PDiag(diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT); break; } } @@ -288,7 +290,9 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { break; case PotentiallyPotentiallyEvaluated: - // FIXME: queue it! + ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), + PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT); break; } } @@ -6488,7 +6492,10 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, break; case PotentiallyPotentiallyEvaluated: - // FIXME: Queue it! + ExprEvalContexts.back().addDiagnostic(BuiltinLoc, + PDiag(diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType()); DidWarnAboutNonPOD = true; break; } @@ -6957,16 +6964,26 @@ Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); ExprEvalContexts.pop_back(); - if (Rec.Context == PotentiallyPotentiallyEvaluated && - Rec.PotentiallyReferenced) { - // Mark any remaining declarations in the current position of the stack - // as "referenced". If they were not meant to be referenced, semantic - // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - for (PotentiallyReferencedDecls::iterator - I = Rec.PotentiallyReferenced->begin(), - IEnd = Rec.PotentiallyReferenced->end(); - I != IEnd; ++I) - MarkDeclarationReferenced(I->first, I->second); + if (Rec.Context == PotentiallyPotentiallyEvaluated) { + if (Rec.PotentiallyReferenced) { + // Mark any remaining declarations in the current position of the stack + // as "referenced". If they were not meant to be referenced, semantic + // analysis would have eliminated them (e.g., in ActOnCXXTypeId). + for (PotentiallyReferencedDecls::iterator + I = Rec.PotentiallyReferenced->begin(), + IEnd = Rec.PotentiallyReferenced->end(); + I != IEnd; ++I) + MarkDeclarationReferenced(I->first, I->second); + } + + if (Rec.PotentiallyDiagnosed) { + // Emit any pending diagnostics. + for (PotentiallyEmittedDiagnostics::iterator + I = Rec.PotentiallyDiagnosed->begin(), + IEnd = Rec.PotentiallyDiagnosed->end(); + I != IEnd; ++I) + Diag(I->first, I->second); + } } // When are coming out of an unevaluated context, clear out any diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp index db519d7161..f913531a27 100644 --- a/test/SemaCXX/vararg-non-pod.cpp +++ b/test/SemaCXX/vararg-non-pod.cpp @@ -75,3 +75,16 @@ class Foo { int Helper(...); const int size = sizeof(Helper(Foo())); + +namespace std { + class type_info { }; +} + +struct Base { virtual ~Base(); }; +Base &get_base(...); +int eat_base(...); + +void test_typeid(Base &base) { + (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'struct Base' through variadic function; call will abort at runtime}} + (void)typeid(eat_base(base)); // okay +} |