зеркало из https://github.com/microsoft/clang-1.git
reimplement DeclStmt handling so that we correctly handle intermixed
VLA's and statement expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69491 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
5b40e0cebc
Коммит
2b7b2ca64a
|
@ -2905,10 +2905,6 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
|
|||
return DeclPtrTy::make(FD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// TODO: statement expressions, for (int x[n]; ;), case.
|
||||
|
||||
/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps
|
||||
/// into VLA and other protected scopes. For example, this rejects:
|
||||
/// goto L;
|
||||
|
@ -2945,7 +2941,6 @@ class JumpScopeChecker {
|
|||
public:
|
||||
JumpScopeChecker(CompoundStmt *Body, Sema &S);
|
||||
private:
|
||||
bool StatementCreatesScope(DeclStmt *S, unsigned ParentScope);
|
||||
void BuildScopeInformation(Stmt *S, unsigned ParentScope);
|
||||
void VerifyJumps();
|
||||
void CheckJump(Stmt *From, Stmt *To,
|
||||
|
@ -2966,39 +2961,20 @@ JumpScopeChecker::JumpScopeChecker(CompoundStmt *Body, Sema &s) : S(s) {
|
|||
VerifyJumps();
|
||||
}
|
||||
|
||||
/// StatementCreatesScope - Return true if the specified statement should start
|
||||
/// a new cleanup scope that cannot be entered with a goto. When this returns
|
||||
/// true it pushes a new scope onto the top of Scopes, indicating what scope to
|
||||
/// use for sub-statements.
|
||||
bool JumpScopeChecker::StatementCreatesScope(DeclStmt *DS,
|
||||
unsigned ParentScope) {
|
||||
// The decl statement creates a scope if any of the decls in it are VLAs or
|
||||
// have the cleanup attribute.
|
||||
for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
|
||||
I != E; ++I) {
|
||||
if (VarDecl *D = dyn_cast<VarDecl>(*I)) {
|
||||
if (D->getType()->isVariablyModifiedType()) {
|
||||
Scopes.push_back(GotoScope(ParentScope,
|
||||
diag::note_protected_by_vla,
|
||||
D->getLocation()));
|
||||
return true; // FIXME: Handle int X[n], Y[n+1];
|
||||
}
|
||||
if (D->hasAttr<CleanupAttr>()) {
|
||||
Scopes.push_back(GotoScope(ParentScope,
|
||||
diag::note_protected_by_cleanup,
|
||||
D->getLocation()));
|
||||
return true;
|
||||
}
|
||||
} else if (TypedefDecl *D = dyn_cast<TypedefDecl>(*I)) {
|
||||
if (D->getUnderlyingType()->isVariablyModifiedType()) {
|
||||
Scopes.push_back(GotoScope(ParentScope,
|
||||
diag::note_protected_by_vla_typedef,
|
||||
D->getLocation()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
|
||||
/// diagnostic that should be emitted if control goes over it. If not, return 0.
|
||||
static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (VD->getType()->isVariablyModifiedType())
|
||||
return diag::note_protected_by_vla;
|
||||
if (VD->hasAttr<CleanupAttr>())
|
||||
return diag::note_protected_by_cleanup;
|
||||
} else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
||||
if (TD->getUnderlyingType()->isVariablyModifiedType())
|
||||
return diag::note_protected_by_vla_typedef;
|
||||
}
|
||||
return false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3029,16 +3005,23 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
|
|||
|
||||
// If this is a declstmt with a VLA definition, it defines a scope from here
|
||||
// to the end of the containing context.
|
||||
if (isa<DeclStmt>(SubStmt) &&
|
||||
// If StatementCreatesScope returns true, then it pushed a new scope
|
||||
// onto Scopes.
|
||||
StatementCreatesScope(cast<DeclStmt>(SubStmt), ParentScope)) {
|
||||
// FIXME: what about substatements (initializers) of the DeclStmt itself?
|
||||
// TODO: int x = ({ int x[n]; label: ... }); // decl stmts matter.
|
||||
|
||||
// Continue analyzing the remaining statements in this scope with a new
|
||||
// parent scope ID.
|
||||
ParentScope = Scopes.size()-1;
|
||||
if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) {
|
||||
// The decl statement creates a scope if any of the decls in it are VLAs or
|
||||
// have the cleanup attribute.
|
||||
for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
|
||||
I != E; ++I) {
|
||||
// If this decl causes a new scope, push and switch to it.
|
||||
if (unsigned Diag = GetDiagForGotoScopeDecl(*I)) {
|
||||
Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation()));
|
||||
ParentScope = Scopes.size()-1;
|
||||
}
|
||||
|
||||
// If the decl has an initializer, walk it with the potentially new
|
||||
// scope we just installed.
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(*I))
|
||||
if (Expr *Init = VD->getInit())
|
||||
BuildScopeInformation(Init, ParentScope);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,35 @@ int test8(int x) {
|
|||
int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
||||
L3: 4; });
|
||||
|
||||
goto L4; // expected-error {{illegal goto into protected scope}}
|
||||
{
|
||||
int A[x], // expected-note {{jump bypasses initialization of variable length array}}
|
||||
B[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
||||
L4: ;
|
||||
}
|
||||
|
||||
{
|
||||
L5: ;// ok
|
||||
int A[x], B = ({ if (x)
|
||||
goto L5;
|
||||
else
|
||||
goto L6;
|
||||
4; });
|
||||
L6:; // ok.
|
||||
}
|
||||
|
||||
{
|
||||
L7: ;// ok
|
||||
int A[x], B = ({ if (x)
|
||||
goto L7;
|
||||
else
|
||||
goto L8; // expected-error {{illegal goto into protected scope}}
|
||||
4; }),
|
||||
C[x]; // expected-note {{jump bypasses initialization of variable length array}}
|
||||
L8:; // bad
|
||||
}
|
||||
|
||||
|
||||
// Statement expressions 2.
|
||||
goto L1; // expected-error {{illegal goto into protected scope}}
|
||||
return x == ({
|
||||
|
|
Загрузка…
Ссылка в новой задаче