forked from OSchip/llvm-project
				
			Refactor and fix checking for initialization of flexible array members. The old version had the checks scattered across the code, missed some checks, and had a couple nasty bugs in existing checks.
Fixes PR10648 and another similar accepts-invalid bug. llvm-svn: 138398
This commit is contained in:
		
							parent
							
								
									01a325a40e
								
							
						
					
					
						commit
						3fa64df543
					
				| 
						 | 
					@ -2716,8 +2716,8 @@ def ext_flexible_array_in_struct : Extension<
 | 
				
			||||||
  "%0 may not be nested in a struct due to flexible array member">;
 | 
					  "%0 may not be nested in a struct due to flexible array member">;
 | 
				
			||||||
def ext_flexible_array_in_array : Extension<
 | 
					def ext_flexible_array_in_array : Extension<
 | 
				
			||||||
  "%0 may not be used as an array element due to flexible array member">;
 | 
					  "%0 may not be used as an array element due to flexible array member">;
 | 
				
			||||||
def err_flexible_array_init_nonempty : Error<
 | 
					def err_flexible_array_init : Error<
 | 
				
			||||||
  "non-empty initialization of flexible array member inside subobject">;
 | 
					  "initialization of flexible array member is not allowed">;
 | 
				
			||||||
def ext_flexible_array_empty_aggregate_ms : Extension<
 | 
					def ext_flexible_array_empty_aggregate_ms : Extension<
 | 
				
			||||||
  "flexible array member %0 in otherwise empty %select{struct|class}1 "
 | 
					  "flexible array member %0 in otherwise empty %select{struct|class}1 "
 | 
				
			||||||
  "is a Microsoft extension">, InGroup<Microsoft>;
 | 
					  "is a Microsoft extension">, InGroup<Microsoft>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5741,27 +5741,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
 | 
				
			||||||
    Init->setType(DclT);
 | 
					    Init->setType(DclT);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  // If this variable is a local declaration with record type, make sure it
 | 
					 | 
				
			||||||
  // doesn't have a flexible member initialization.  We only support this as a
 | 
					 | 
				
			||||||
  // global/static definition.
 | 
					 | 
				
			||||||
  if (VDecl->hasLocalStorage())
 | 
					 | 
				
			||||||
    if (const RecordType *RT = VDecl->getType()->getAs<RecordType>())
 | 
					 | 
				
			||||||
      if (RT->getDecl()->hasFlexibleArrayMember()) {
 | 
					 | 
				
			||||||
        // Check whether the initializer tries to initialize the flexible
 | 
					 | 
				
			||||||
        // array member itself to anything other than an empty initializer list.
 | 
					 | 
				
			||||||
        if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
 | 
					 | 
				
			||||||
          unsigned Index = std::distance(RT->getDecl()->field_begin(),
 | 
					 | 
				
			||||||
                                         RT->getDecl()->field_end()) - 1;
 | 
					 | 
				
			||||||
          if (Index < ILE->getNumInits() &&
 | 
					 | 
				
			||||||
              !(isa<InitListExpr>(ILE->getInit(Index)) &&
 | 
					 | 
				
			||||||
                cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) {
 | 
					 | 
				
			||||||
            Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable);
 | 
					 | 
				
			||||||
            VDecl->setInvalidDecl();
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  // Check any implicit conversions within the expression.
 | 
					  // Check any implicit conversions within the expression.
 | 
				
			||||||
  CheckImplicitConversions(Init, VDecl->getLocation());
 | 
					  CheckImplicitConversions(Init, VDecl->getLocation());
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -249,6 +249,9 @@ class InitListChecker {
 | 
				
			||||||
                               InitListExpr *ILE, bool &RequiresSecondPass);
 | 
					                               InitListExpr *ILE, bool &RequiresSecondPass);
 | 
				
			||||||
  void FillInValueInitializations(const InitializedEntity &Entity,
 | 
					  void FillInValueInitializations(const InitializedEntity &Entity,
 | 
				
			||||||
                                  InitListExpr *ILE, bool &RequiresSecondPass);
 | 
					                                  InitListExpr *ILE, bool &RequiresSecondPass);
 | 
				
			||||||
 | 
					  bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
 | 
				
			||||||
 | 
					                              Expr *InitExpr, FieldDecl *Field,
 | 
				
			||||||
 | 
					                              bool TopLevelObject);
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  InitListChecker(Sema &S, const InitializedEntity &Entity,
 | 
					  InitListChecker(Sema &S, const InitializedEntity &Entity,
 | 
				
			||||||
                  InitListExpr *IL, QualType &T);
 | 
					                  InitListExpr *IL, QualType &T);
 | 
				
			||||||
| 
						 | 
					@ -1113,6 +1116,43 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
 | 
				
			||||||
 | 
					                                             Expr *InitExpr,
 | 
				
			||||||
 | 
					                                             FieldDecl *Field,
 | 
				
			||||||
 | 
					                                             bool TopLevelObject) {
 | 
				
			||||||
 | 
					  // Handle GNU flexible array initializers.
 | 
				
			||||||
 | 
					  unsigned FlexArrayDiag;
 | 
				
			||||||
 | 
					  if (isa<InitListExpr>(InitExpr) &&
 | 
				
			||||||
 | 
					      cast<InitListExpr>(InitExpr)->getNumInits() == 0) {
 | 
				
			||||||
 | 
					    // Empty flexible array init always allowed as an extension
 | 
				
			||||||
 | 
					    FlexArrayDiag = diag::ext_flexible_array_init;
 | 
				
			||||||
 | 
					  } else if (SemaRef.getLangOptions().CPlusPlus) {
 | 
				
			||||||
 | 
					    // Disallow flexible array init in C++; it is not required for gcc
 | 
				
			||||||
 | 
					    // compatibility, and it needs work to IRGen correctly in general.
 | 
				
			||||||
 | 
					    FlexArrayDiag = diag::err_flexible_array_init;
 | 
				
			||||||
 | 
					  } else if (!TopLevelObject) {
 | 
				
			||||||
 | 
					    // Disallow flexible array init on non-top-level object
 | 
				
			||||||
 | 
					    FlexArrayDiag = diag::err_flexible_array_init;
 | 
				
			||||||
 | 
					  } else if (Entity.getKind() != InitializedEntity::EK_Variable) {
 | 
				
			||||||
 | 
					    // Disallow flexible array init on anything which is not a variable.
 | 
				
			||||||
 | 
					    FlexArrayDiag = diag::err_flexible_array_init;
 | 
				
			||||||
 | 
					  } else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) {
 | 
				
			||||||
 | 
					    // Disallow flexible array init on local variables.
 | 
				
			||||||
 | 
					    FlexArrayDiag = diag::err_flexible_array_init;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // Allow other cases.
 | 
				
			||||||
 | 
					    FlexArrayDiag = diag::ext_flexible_array_init;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  SemaRef.Diag(InitExpr->getSourceRange().getBegin(),
 | 
				
			||||||
 | 
					               FlexArrayDiag)
 | 
				
			||||||
 | 
					    << InitExpr->getSourceRange().getBegin();
 | 
				
			||||||
 | 
					  SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
 | 
				
			||||||
 | 
					    << Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return FlexArrayDiag != diag::ext_flexible_array_init;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
 | 
					void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
 | 
				
			||||||
                                            InitListExpr *IList,
 | 
					                                            InitListExpr *IList,
 | 
				
			||||||
                                            QualType DeclType,
 | 
					                                            QualType DeclType,
 | 
				
			||||||
| 
						 | 
					@ -1239,24 +1279,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
 | 
				
			||||||
      Index >= IList->getNumInits())
 | 
					      Index >= IList->getNumInits())
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Handle GNU flexible array initializers.
 | 
					  if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field,
 | 
				
			||||||
  if (!TopLevelObject &&
 | 
					                             TopLevelObject)) {
 | 
				
			||||||
      (!isa<InitListExpr>(IList->getInit(Index)) ||
 | 
					 | 
				
			||||||
       cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) {
 | 
					 | 
				
			||||||
    SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
 | 
					 | 
				
			||||||
                  diag::err_flexible_array_init_nonempty)
 | 
					 | 
				
			||||||
      << IList->getInit(Index)->getSourceRange().getBegin();
 | 
					 | 
				
			||||||
    SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
 | 
					 | 
				
			||||||
      << *Field;
 | 
					 | 
				
			||||||
    hadError = true;
 | 
					    hadError = true;
 | 
				
			||||||
    ++Index;
 | 
					    ++Index;
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
 | 
					 | 
				
			||||||
                 diag::ext_flexible_array_init)
 | 
					 | 
				
			||||||
      << IList->getInit(Index)->getSourceRange().getBegin();
 | 
					 | 
				
			||||||
    SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
 | 
					 | 
				
			||||||
      << *Field;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  InitializedEntity MemberEntity =
 | 
					  InitializedEntity MemberEntity =
 | 
				
			||||||
| 
						 | 
					@ -1567,16 +1594,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
 | 
				
			||||||
        Invalid = true;
 | 
					        Invalid = true;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Handle GNU flexible array initializers.
 | 
					      // Check GNU flexible array initializer.
 | 
				
			||||||
      if (!Invalid && !TopLevelObject &&
 | 
					      if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field,
 | 
				
			||||||
          cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) {
 | 
					                                             TopLevelObject))
 | 
				
			||||||
        SemaRef.Diag(DIE->getSourceRange().getBegin(),
 | 
					 | 
				
			||||||
                      diag::err_flexible_array_init_nonempty)
 | 
					 | 
				
			||||||
          << DIE->getSourceRange().getBegin();
 | 
					 | 
				
			||||||
        SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
 | 
					 | 
				
			||||||
          << *Field;
 | 
					 | 
				
			||||||
        Invalid = true;
 | 
					        Invalid = true;
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (Invalid) {
 | 
					      if (Invalid) {
 | 
				
			||||||
        ++Index;
 | 
					        ++Index;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,9 +7,7 @@ struct one {
 | 
				
			||||||
struct one x2 = { 5, 1, 2, 3 }; // expected-warning{{flexible array initialization is a GNU extension}}
 | 
					struct one x2 = { 5, 1, 2, 3 }; // expected-warning{{flexible array initialization is a GNU extension}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test() {
 | 
					void test() {
 | 
				
			||||||
  struct one x3 = {5, {1, 2, 3}}; // \
 | 
					  struct one x3 = {5, {1, 2, 3}}; // expected-error{{initialization of flexible array member is not allowed}}
 | 
				
			||||||
   // expected-warning{{flexible array initialization is a GNU extension}} \
 | 
					 | 
				
			||||||
   // expected-error {{non-static initialization of a variable with flexible array member}}
 | 
					 | 
				
			||||||
  struct one x3a = { 5 };
 | 
					  struct one x3a = { 5 };
 | 
				
			||||||
  struct one x3b = { .a = 5 };
 | 
					  struct one x3b = { .a = 5 };
 | 
				
			||||||
  struct one x3c = { 5, {} }; // expected-warning{{use of GNU empty initializer extension}} \
 | 
					  struct one x3c = { 5, {} }; // expected-warning{{use of GNU empty initializer extension}} \
 | 
				
			||||||
| 
						 | 
					@ -19,22 +17,23 @@ void test() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct foo { 
 | 
					struct foo { 
 | 
				
			||||||
  int x; 
 | 
					  int x; 
 | 
				
			||||||
  int y[]; // expected-note 6 {{initialized flexible array member 'y' is here}}
 | 
					  int y[]; // expected-note 8 {{initialized flexible array member 'y' is here}}
 | 
				
			||||||
}; 
 | 
					}; 
 | 
				
			||||||
struct bar { struct foo z; }; // expected-warning {{'z' may not be nested in a struct due to flexible array member}}
 | 
					struct bar { struct foo z; }; // expected-warning {{'z' may not be nested in a struct due to flexible array member}}
 | 
				
			||||||
     
 | 
					     
 | 
				
			||||||
struct foo a = { 1, { 2, 3, 4 } };        // expected-warning{{flexible array initialization is a GNU extension}}
 | 
					struct foo a = { 1, { 2, 3, 4 } };        // expected-warning{{flexible array initialization is a GNU extension}}
 | 
				
			||||||
struct bar b = { { 1, { 2, 3, 4 } } };    // expected-error{{non-empty initialization of flexible array member inside subobject}}
 | 
					struct bar b = { { 1, { 2, 3, 4 } } };    // expected-error{{initialization of flexible array member is not allowed}}
 | 
				
			||||||
struct bar c = { { 1, { } } };            // // expected-warning{{flexible array initialization is a GNU extension}} \
 | 
					struct bar c = { { 1, { } } };            // // expected-warning{{flexible array initialization is a GNU extension}} \
 | 
				
			||||||
              // expected-warning{{use of GNU empty initializer extension}} \
 | 
					              // expected-warning{{use of GNU empty initializer extension}} \
 | 
				
			||||||
              // expected-warning{{zero size arrays are an extension}}
 | 
					              // expected-warning{{zero size arrays are an extension}}
 | 
				
			||||||
struct foo d[1] = { { 1, { 2, 3, 4 } } };  // expected-warning{{'struct foo' may not be used as an array element due to flexible array member}} \
 | 
					struct foo d[1] = { { 1, { 2, 3, 4 } } };  // expected-warning{{'struct foo' may not be used as an array element due to flexible array member}} \
 | 
				
			||||||
              // expected-error{{non-empty initialization of flexible array member inside subobject}}
 | 
					              // expected-error{{initialization of flexible array member is not allowed}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct foo desig_foo = { .y = {2, 3, 4} };
 | 
					struct foo desig_foo = { .y = {2, 3, 4} }; // expected-warning{{flexible array initialization is a GNU extension}}
 | 
				
			||||||
struct bar desig_bar = { .z.y = { } }; // expected-warning{{use of GNU empty initializer extension}} \
 | 
					struct bar desig_bar = { .z.y = { } }; // expected-warning{{use of GNU empty initializer extension}} \
 | 
				
			||||||
  // expected-warning{{zero size arrays are an extension}}
 | 
					  // expected-warning{{zero size arrays are an extension}} \
 | 
				
			||||||
struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
 | 
					  // expected-warning{{flexible array initialization is a GNU extension}}
 | 
				
			||||||
 | 
					struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{initialization of flexible array member is not allowed}}
 | 
				
			||||||
struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
 | 
					struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct point {
 | 
					struct point {
 | 
				
			||||||
| 
						 | 
					@ -68,13 +67,25 @@ struct Y {
 | 
				
			||||||
// PR8217
 | 
					// PR8217
 | 
				
			||||||
struct PR8217a {
 | 
					struct PR8217a {
 | 
				
			||||||
  int  i;
 | 
					  int  i;
 | 
				
			||||||
  char v[];
 | 
					  char v[]; // expected-note 2 {{initialized flexible array member 'v' is here}}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PR8217() {
 | 
					void PR8217() {
 | 
				
			||||||
  struct PR8217a foo1 = { .i = 0, .v = "foo" }; // expected-error {{non-static initialization of a variable with flexible array member}}
 | 
					  struct PR8217a foo1 = { .i = 0, .v = "foo" }; // expected-error {{initialization of flexible array member is not allowed}}
 | 
				
			||||||
  struct PR8217a foo2 = { .i = 0 };
 | 
					  struct PR8217a foo2 = { .i = 0 };
 | 
				
			||||||
  struct PR8217a foo3 = { .i = 0, .v = { 'b', 'a', 'r', '\0' } }; // expected-error {{non-static initialization of a variable with flexible array member}}
 | 
					  struct PR8217a foo3 = { .i = 0, .v = { 'b', 'a', 'r', '\0' } }; // expected-error {{initialization of flexible array member is not allowed}}
 | 
				
			||||||
  struct PR8217a bar;
 | 
					  struct PR8217a bar;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct PR10648 {
 | 
				
			||||||
 | 
					 unsigned long n;
 | 
				
			||||||
 | 
					 int v[]; // expected-note {{initialized flexible array member 'v' is here}}
 | 
				
			||||||
 | 
					} PR10648;
 | 
				
			||||||
 | 
					int f10648() { 
 | 
				
			||||||
 | 
					  return (PR10648){2, {3, 4}}.v[1]; // expected-error {{initialization of flexible array member is not allowed}}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct FlexWithUnnamedBitfield { int : 10; int x; int y[]; }; // expected-note {{initialized flexible array member 'y' is here}}
 | 
				
			||||||
 | 
					void TestFlexWithUnnamedBitfield() {
 | 
				
			||||||
 | 
					  struct FlexWithUnnamedBitfield x = {10, {3}}; // expected-error {{initialization of flexible array member is not allowed}}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue