20 #include "llvm/ADT/BitVector.h" 21 using namespace clang;
31 class JumpScopeChecker {
36 const bool Permissive;
59 GotoScope(
unsigned parentScope,
unsigned InDiag,
unsigned OutDiag,
61 : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}
65 llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
73 JumpScopeChecker(
Stmt *Body,
Sema &S);
75 void BuildScopeInformation(
Decl *D,
unsigned &ParentScope);
77 unsigned &ParentScope);
78 void BuildScopeInformation(
Stmt *S,
unsigned &origParentScope);
81 void VerifyIndirectOrAsmJumps(
bool IsAsmGoto);
84 unsigned TargetScope);
86 unsigned JumpDiag,
unsigned JumpDiagWarning,
87 unsigned JumpDiagCXX98Compat);
90 unsigned GetDeepestCommonScope(
unsigned A,
unsigned B);
94 #define CHECK_PERMISSIVE(x) (assert(Permissive || !(x)), (Permissive && (x))) 96 JumpScopeChecker::JumpScopeChecker(
Stmt *Body,
Sema &s)
97 : S(s), Permissive(s.hasAnyUnrecoverableErrorsInThisFunction()) {
103 unsigned BodyParentScope = 0;
104 BuildScopeInformation(Body, BodyParentScope);
108 VerifyIndirectOrAsmJumps(
false);
109 VerifyIndirectOrAsmJumps(
true);
114 unsigned JumpScopeChecker::GetDeepestCommonScope(
unsigned A,
unsigned B) {
119 assert(Scopes[B].ParentScope < B);
120 B = Scopes[B].ParentScope;
122 assert(Scopes[A].ParentScope < A);
123 A = Scopes[A].ParentScope;
134 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
136 unsigned OutDiag = 0;
138 if (VD->getType()->isVariablyModifiedType())
139 InDiag = diag::note_protected_by_vla;
141 if (VD->hasAttr<BlocksAttr>())
142 return ScopePair(diag::note_protected_by___block,
143 diag::note_exits___block);
145 if (VD->hasAttr<CleanupAttr>())
146 return ScopePair(diag::note_protected_by_cleanup,
147 diag::note_exits_cleanup);
149 if (VD->hasLocalStorage()) {
150 switch (VD->getType().isDestructedType()) {
151 case QualType::DK_objc_strong_lifetime:
152 return ScopePair(diag::note_protected_by_objc_strong_init,
153 diag::note_exits_objc_strong);
155 case QualType::DK_objc_weak_lifetime:
156 return ScopePair(diag::note_protected_by_objc_weak_init,
157 diag::note_exits_objc_weak);
159 case QualType::DK_nontrivial_c_struct:
160 return ScopePair(diag::note_protected_by_non_trivial_c_struct_init,
161 diag::note_exits_dtor);
163 case QualType::DK_cxx_destructor:
164 OutDiag = diag::note_exits_dtor;
167 case QualType::DK_none:
172 const Expr *Init = VD->getInit();
188 InDiag = diag::note_protected_by_variable_init;
196 VD->getInitStyle() == VarDecl::CallInit) {
198 InDiag = diag::note_protected_by_variable_nontriv_destructor;
200 InDiag = diag::note_protected_by_variable_non_pod;
211 if (TD->getUnderlyingType()->isVariablyModifiedType())
213 ? diag::note_protected_by_vla_typedef
214 : diag::note_protected_by_vla_type_alias,
222 void JumpScopeChecker::BuildScopeInformation(
Decl *D,
unsigned &ParentScope) {
225 if (Diags.first || Diags.second) {
226 Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
228 ParentScope = Scopes.size()-1;
233 if (
VarDecl *VD = dyn_cast<VarDecl>(D))
234 if (
Expr *Init = VD->getInit())
235 BuildScopeInformation(Init, ParentScope);
239 void JumpScopeChecker::BuildScopeInformation(
VarDecl *D,
241 unsigned &ParentScope) {
248 if (destructKind != QualType::DK_none) {
249 std::pair<unsigned,unsigned> Diags;
250 switch (destructKind) {
251 case QualType::DK_cxx_destructor:
252 Diags =
ScopePair(diag::note_enters_block_captures_cxx_obj,
253 diag::note_exits_block_captures_cxx_obj);
255 case QualType::DK_objc_strong_lifetime:
256 Diags =
ScopePair(diag::note_enters_block_captures_strong,
257 diag::note_exits_block_captures_strong);
259 case QualType::DK_objc_weak_lifetime:
260 Diags =
ScopePair(diag::note_enters_block_captures_weak,
261 diag::note_exits_block_captures_weak);
263 case QualType::DK_nontrivial_c_struct:
264 Diags =
ScopePair(diag::note_enters_block_captures_non_trivial_c_struct,
265 diag::note_exits_block_captures_non_trivial_c_struct);
267 case QualType::DK_none:
268 llvm_unreachable(
"non-lifetime captured variable");
273 Scopes.push_back(GotoScope(ParentScope,
274 Diags.first, Diags.second, Loc));
275 ParentScope = Scopes.size()-1;
283 void JumpScopeChecker::BuildScopeInformation(
Stmt *S,
284 unsigned &origParentScope) {
288 unsigned independentParentScope = origParentScope;
289 unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
290 ? origParentScope : independentParentScope);
292 unsigned StmtsToSkip = 0u;
296 case Stmt::AddrLabelExprClass:
297 IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
300 case Stmt::ObjCForCollectionStmtClass: {
301 auto *CS = cast<ObjCForCollectionStmt>(S);
302 unsigned Diag = diag::note_protected_by_objc_fast_enumeration;
303 unsigned NewParentScope = Scopes.size();
304 Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->
getBeginLoc()));
305 BuildScopeInformation(CS->getBody(), NewParentScope);
309 case Stmt::IndirectGotoStmtClass:
315 if (cast<IndirectGotoStmt>(S)->getConstantTarget()) {
316 LabelAndGotoScopes[S] = ParentScope;
321 LabelAndGotoScopes[S] = ParentScope;
322 IndirectJumps.push_back(S);
325 case Stmt::SwitchStmtClass:
328 if (
Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
329 BuildScopeInformation(Init, ParentScope);
332 if (
VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
333 BuildScopeInformation(Var, ParentScope);
338 case Stmt::GotoStmtClass:
341 LabelAndGotoScopes[S] = ParentScope;
345 case Stmt::GCCAsmStmtClass:
346 if (
auto *GS = dyn_cast<GCCAsmStmt>(S))
347 if (GS->isAsmGoto()) {
350 LabelAndGotoScopes[S] = ParentScope;
351 AsmJumps.push_back(GS);
352 for (
auto *E : GS->labels())
353 AsmJumpTargets.push_back(E->getLabel());
357 case Stmt::IfStmtClass: {
358 IfStmt *IS = cast<IfStmt>(S);
362 unsigned Diag = IS->
isConstexpr() ? diag::note_protected_by_constexpr_if
363 : diag::note_protected_by_if_available;
366 BuildScopeInformation(Var, ParentScope);
369 unsigned NewParentScope = Scopes.size();
370 Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->
getBeginLoc()));
371 BuildScopeInformation(IS->
getCond(), NewParentScope);
374 NewParentScope = Scopes.size();
375 Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->
getBeginLoc()));
376 BuildScopeInformation(IS->
getThen(), NewParentScope);
378 NewParentScope = Scopes.size();
379 Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->
getBeginLoc()));
380 BuildScopeInformation(Else, NewParentScope);
385 case Stmt::CXXTryStmtClass: {
388 unsigned NewParentScope = Scopes.size();
389 Scopes.push_back(GotoScope(ParentScope,
390 diag::note_protected_by_cxx_try,
391 diag::note_exits_cxx_try,
394 BuildScopeInformation(TryBlock, NewParentScope);
400 unsigned NewParentScope = Scopes.size();
401 Scopes.push_back(GotoScope(ParentScope,
402 diag::note_protected_by_cxx_catch,
403 diag::note_exits_cxx_catch,
410 case Stmt::SEHTryStmtClass: {
413 unsigned NewParentScope = Scopes.size();
414 Scopes.push_back(GotoScope(ParentScope,
415 diag::note_protected_by_seh_try,
416 diag::note_exits_seh_try,
419 BuildScopeInformation(TryBlock, NewParentScope);
424 unsigned NewParentScope = Scopes.size();
425 Scopes.push_back(GotoScope(ParentScope,
426 diag::note_protected_by_seh_except,
427 diag::note_exits_seh_except,
428 Except->getSourceRange().getBegin()));
429 BuildScopeInformation(Except->getBlock(), NewParentScope);
431 unsigned NewParentScope = Scopes.size();
432 Scopes.push_back(GotoScope(ParentScope,
433 diag::note_protected_by_seh_finally,
434 diag::note_exits_seh_finally,
435 Finally->getSourceRange().getBegin()));
436 BuildScopeInformation(Finally->getBlock(), NewParentScope);
442 case Stmt::DeclStmtClass: {
448 for (
auto *I : DS->
decls())
449 BuildScopeInformation(I, origParentScope);
453 case Stmt::ObjCAtTryStmtClass: {
459 unsigned NewParentScope = Scopes.size();
460 Scopes.push_back(GotoScope(ParentScope,
461 diag::note_protected_by_objc_try,
462 diag::note_exits_objc_try,
465 BuildScopeInformation(TryPart, NewParentScope);
471 unsigned NewParentScope = Scopes.size();
472 Scopes.push_back(GotoScope(ParentScope,
473 diag::note_protected_by_objc_catch,
474 diag::note_exits_objc_catch,
477 BuildScopeInformation(AC->
getCatchBody(), NewParentScope);
482 unsigned NewParentScope = Scopes.size();
483 Scopes.push_back(GotoScope(ParentScope,
484 diag::note_protected_by_objc_finally,
485 diag::note_exits_objc_finally,
486 AF->getAtFinallyLoc()));
487 BuildScopeInformation(AF, NewParentScope);
493 case Stmt::ObjCAtSynchronizedStmtClass: {
503 unsigned NewParentScope = Scopes.size();
504 Scopes.push_back(GotoScope(ParentScope,
505 diag::note_protected_by_objc_synchronized,
506 diag::note_exits_objc_synchronized,
508 BuildScopeInformation(AS->
getSynchBody(), NewParentScope);
512 case Stmt::ObjCAutoreleasePoolStmtClass: {
517 unsigned NewParentScope = Scopes.size();
518 Scopes.push_back(GotoScope(ParentScope,
519 diag::note_protected_by_objc_autoreleasepool,
520 diag::note_exits_objc_autoreleasepool,
522 BuildScopeInformation(AS->
getSubStmt(), NewParentScope);
526 case Stmt::ExprWithCleanupsClass: {
533 for (
const auto &CI : BDecl->
captures()) {
534 VarDecl *variable = CI.getVariable();
535 BuildScopeInformation(variable, BDecl, origParentScope);
541 case Stmt::MaterializeTemporaryExprClass: {
548 const Expr *ExtendedObject =
550 CommaLHS, Adjustments);
552 Scopes.push_back(GotoScope(ParentScope, 0,
553 diag::note_exits_temporary_dtor,
555 origParentScope = Scopes.size()-1;
561 case Stmt::CaseStmtClass:
562 case Stmt::DefaultStmtClass:
563 case Stmt::LabelStmtClass:
564 LabelAndGotoScopes[S] = ParentScope;
584 if (
SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
585 Next = SC->getSubStmt();
586 else if (
LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
587 Next = LS->getSubStmt();
591 LabelAndGotoScopes[SubStmt] = ParentScope;
596 BuildScopeInformation(SubStmt, ParentScope);
602 void JumpScopeChecker::VerifyJumps() {
603 while (!Jumps.empty()) {
604 Stmt *Jump = Jumps.pop_back_val();
607 if (
GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
609 if (GS->getLabel()->getStmt()) {
610 CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
611 diag::err_goto_into_protected_scope,
612 diag::ext_goto_into_protected_scope,
613 diag::warn_cxx98_compat_goto_into_protected_scope);
622 CheckJump(IGS, Target->
getStmt(), IGS->getGotoLoc(),
623 diag::err_goto_into_protected_scope,
624 diag::ext_goto_into_protected_scope,
625 diag::warn_cxx98_compat_goto_into_protected_scope);
635 if (
CaseStmt *CS = dyn_cast<CaseStmt>(SC))
636 Loc = CS->getBeginLoc();
637 else if (
DefaultStmt *DS = dyn_cast<DefaultStmt>(SC))
638 Loc = DS->getBeginLoc();
640 Loc = SC->getBeginLoc();
641 CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0,
642 diag::warn_cxx98_compat_switch_into_protected_scope);
665 void JumpScopeChecker::VerifyIndirectOrAsmJumps(
bool IsAsmGoto) {
667 if (GotoJumps.empty())
670 IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets;
673 if (JumpTargets.empty()) {
674 assert(!IsAsmGoto &&
"only indirect goto can get here");
675 S.Diag(GotoJumps[0]->getBeginLoc(),
676 diag::err_indirect_goto_without_addrlabel);
682 typedef std::pair<unsigned, Stmt*> JumpScope;
685 llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
692 unsigned IGScope = LabelAndGotoScopes[IG];
693 Stmt *&Entry = JumpScopesMap[IGScope];
694 if (!Entry) Entry = IG;
696 JumpScopes.reserve(JumpScopesMap.size());
697 for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(),
698 E = JumpScopesMap.end();
700 JumpScopes.push_back(*I);
706 llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
708 E = JumpTargets.end();
713 unsigned LabelScope = LabelAndGotoScopes[TheLabel->
getStmt()];
715 if (!Target) Target = TheLabel;
726 llvm::BitVector Reachable(Scopes.size(),
false);
727 for (llvm::DenseMap<unsigned,LabelDecl*>::iterator
728 TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) {
729 unsigned TargetScope = TI->first;
737 unsigned Min = TargetScope;
745 if (Scopes[Min].InDiag)
break;
747 Min = Scopes[Min].ParentScope;
753 I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) {
754 unsigned Scope = I->first;
761 bool IsReachable =
false;
763 if (Reachable.test(Scope)) {
766 for (
unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope)
774 if (Scope == 0 || Scope < Min)
break;
777 if (Scopes[Scope].OutDiag)
break;
779 Scope = Scopes[Scope].ParentScope;
783 if (IsReachable)
continue;
785 DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope);
793 return (JumpDiag == diag::err_goto_into_protected_scope &&
794 (InDiagNote == diag::note_protected_by_variable_init ||
795 InDiagNote == diag::note_protected_by_variable_nontriv_destructor));
802 InDiagNote == diag::note_protected_by_variable_non_pod;
810 bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
811 S.
Diag(Jump->
getBeginLoc(), diag::err_indirect_goto_in_protected_scope)
822 for (
unsigned I = 0, E = ToScopes.size(); I != E; ++I)
823 if (Scopes[ToScopes[I]].InDiag)
824 S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag);
828 void JumpScopeChecker::DiagnoseIndirectOrAsmJump(
Stmt *Jump,
unsigned JumpScope,
830 unsigned TargetScope) {
834 unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
835 bool Diagnosed =
false;
838 for (
unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
839 if (Scopes[I].OutDiag) {
841 S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
847 for (
unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)
849 ToScopesCXX98Compat.push_back(I);
850 else if (Scopes[I].InDiag) {
852 S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
856 if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
857 bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
859 diag::warn_cxx98_compat_indirect_goto_in_protected_scope)
863 NoteJumpIntoScopes(ToScopesCXX98Compat);
870 unsigned JumpDiagError,
unsigned JumpDiagWarning,
871 unsigned JumpDiagCXX98Compat) {
877 unsigned FromScope = LabelAndGotoScopes[From];
878 unsigned ToScope = LabelAndGotoScopes[To];
881 if (FromScope == ToScope)
return;
884 if (isa<GotoStmt>(From) || isa<IndirectGotoStmt>(From)) {
887 for (
unsigned I = FromScope; I > ToScope; I = Scopes[I].ParentScope) {
888 if (Scopes[I].InDiag == diag::note_protected_by_seh_finally) {
889 S.Diag(From->
getBeginLoc(), diag::warn_jump_out_of_seh_finally);
895 unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
898 if (CommonScope == ToScope)
return;
904 for (
unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) {
905 if (S.getLangOpts().MSVCCompat && JumpDiagWarning != 0 &&
907 ToScopesWarning.push_back(I);
909 ToScopesCXX98Compat.push_back(I);
910 else if (Scopes[I].InDiag)
911 ToScopesError.push_back(I);
915 if (!ToScopesWarning.empty()) {
916 S.Diag(DiagLoc, JumpDiagWarning);
917 NoteJumpIntoScopes(ToScopesWarning);
921 if (!ToScopesError.empty()) {
922 S.Diag(DiagLoc, JumpDiagError);
923 NoteJumpIntoScopes(ToScopesError);
927 if (ToScopesError.empty() && !ToScopesCXX98Compat.empty()) {
928 S.Diag(DiagLoc, JumpDiagCXX98Compat);
929 NoteJumpIntoScopes(ToScopesCXX98Compat);
933 void JumpScopeChecker::CheckGotoStmt(
GotoStmt *GS) {
935 S.Diag(GS->
getGotoLoc(), diag::err_goto_ms_asm_label)
942 void Sema::DiagnoseInvalidJumps(
Stmt *Body) {
943 (void)JumpScopeChecker(Body, *
this);
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
A (possibly-)qualified type.
const Expr * skipRValueSubobjectAdjustments(SmallVectorImpl< const Expr *> &CommaLHS, SmallVectorImpl< SubobjectAdjustment > &Adjustments) const
Walk outwards from an expression we want to bind a reference to and find the expression whose lifetim...
Stmt - This represents one statement.
const ObjCAtFinallyStmt * getFinallyStmt() const
Retrieve the @finally statement, if any.
CXXCatchStmt * getHandler(unsigned i)
IfStmt - This represents an if/then/else.
static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote)
Return true if a particular error+note combination must be downgraded to a warning in Microsoft mode...
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Decl - This represents one declaration (or definition), e.g.
Stmt * getHandlerBlock() const
bool isPOD() const
Whether this class is a POD-type (C++ [class]p4)
SourceLocation getIdentLoc() const
Represents a call to a C++ constructor.
Represents a C++ constructor within a class.
Represents a prvalue temporary that is written into memory so that a reference can bind to it...
bool isDefaultConstructor() const
Whether this constructor is a default constructor (C++ [class.ctor]p5), which can be used to default-...
Represents a variable declaration or definition.
#define CHECK_PERMISSIVE(x)
Defines the Objective-C statement AST node classes.
Represents an expression – generally a full-expression – that introduces cleanups to be run at the ...
Defines the clang::Expr interface and subclasses for C++ expressions.
const Stmt * getSubStmt() const
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
LabelStmt - Represents a label, which has a substatement.
Expr * GetTemporaryExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue...
SourceLocation getBeginLoc() const LLVM_READONLY
Represents Objective-C's @catch statement.
IndirectGotoStmt - This represents an indirect goto.
Scope - A scope is a transient data structure that is used while parsing the program.
CaseStmt - Represent a case statement.
const LangOptions & getLangOpts() const
const ObjCAtCatchStmt * getCatchStmt(unsigned I) const
Retrieve a @catch statement.
Sema - This implements semantic analysis and AST building for C.
Represents a block literal declaration, which is like an unnamed FunctionDecl.
This represents one expression.
const CompoundStmt * getSynchBody() const
Represents Objective-C's @synchronized statement.
static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump, LabelDecl *Target, bool &Diagnosed)
Produce primary diagnostic for an indirect jump statement.
CXXTryStmt - A C++ try block, including all handlers.
SourceLocation getAtTryLoc() const
Retrieve the location of the @ in the @try.
SourceLocation getBeginLoc() const
LabelDecl * getLabel() const
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
const Stmt * getTryBody() const
Retrieve the @try body.
std::pair< unsigned, unsigned > ScopePair
SwitchCase * getSwitchCaseList()
SourceLocation getAtLoc() const
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
Encodes a location in the source.
const Stmt * getCatchBody() const
unsigned getNumHandlers() const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Represents the declaration of a label.
SourceLocation getGotoLoc() const
bool isMSAsmLabel() const
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after...
SourceLocation getAtCatchLoc() const
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Base class for declarations which introduce a typedef-name.
LabelStmt * getStmt() const
Dataflow Directional Tag Classes.
ArrayRef< Capture > captures() const
StmtClass getStmtClass() const
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined...
SEHExceptStmt * getExceptHandler() const
Returns 0 if not defined.
const Expr * getSynchExpr() const
bool isObjCAvailabilityCheck() const
SwitchStmt - This represents a 'switch' stmt.
unsigned getNumObjects() const
Represents Objective-C's @finally statement.
SEHFinallyStmt * getFinallyHandler() const
GotoStmt - This represents a direct goto.
const SwitchCase * getNextSwitchCase() const
static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D)
GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a diagnostic that should be e...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
VarDecl * getConditionVariable()
Retrieve the variable declared in this "if" statement, if any.
CXXCatchStmt - This represents a C++ catch block.
CleanupObject getObject(unsigned i) const
SourceLocation getAtSynchronizedLoc() const
CompoundStmt * getTryBlock()
Represents Objective-C's @try ... @catch ... @finally statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
unsigned getNumCatchStmts() const
Retrieve the number of @catch statements in this try-catch-finally block.
Automatic storage duration (most local variables).
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
Represents Objective-C's @autoreleasepool Statement.
CompoundStmt * getTryBlock() const
SourceLocation getLocation() const
static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote)
Return true if a particular note should be downgraded to a compatibility warning in C++11 mode...