From: Steve Naroff Date: Sun, 2 Sep 2007 02:04:30 +0000 (+0000) Subject: Start implementing semantic analysis for C initializers. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f009063ab7e05be7781751ff9e4b42630f07a747;p=clang Start implementing semantic analysis for C initializers. Step 1: Start instantiating InitListExpr's. Step 2: Call newly added function Sema::CheckInitializer() from Sema::ParseDeclarator(). Step 3: Give InitListExpr's a preliminary type. Step 4: Start emitting diagnostics for simple assignments. Note: As a result of step 1, the CodeGen/mandel.c test asserts "Unimplemented agg expr!", which is expected. As a result of step 4, the test below now fails. This isn't expected and needs to be investigated (it appears type checking for C++ references is flawed in some way). ******************** TEST 'Sema/cxx-references.cpp' FAILED! ******************** Command: clang -fsyntax-only Sema/cxx-references.cpp Output: Sema/cxx-references.cpp:8:12: warning: incompatible pointer types assigning 'int &*' to 'int *' int *p = &r; ^~ Sema/cxx-references.cpp:10:20: error: incompatible types assigning 'int (int)' to 'int (&)(int)' int (&rg)(int) = g; ^ Sema/cxx-references.cpp:13:18: error: incompatible types assigning 'int [3]' to 'int (&)[3]' int (&ra)[3] = a; ^ Sema/cxx-references.cpp:16:14: error: incompatible types assigning 'int *' to 'int *&' int *& P = Q; ^ 4 diagnostics generated. ******************** TEST 'Sema/cxx-references.cpp' FAILED! ******************** git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41671 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/Sema.h b/Sema/Sema.h index 78b88b78a0..e99e332cf5 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -440,6 +440,10 @@ private: QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc, IdentifierInfo &Comp, SourceLocation CmpLoc); + /// type checking declaration initializers (C99 6.7.8) + QualType CheckInitializer(Expr *simpleInit_or_initList, QualType declType); + bool CheckSingleInitializer(Expr *simpleInit, QualType declType); + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 4d2fd4d515..6d8308a882 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -239,6 +239,63 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return 0; } +bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) { + AssignmentCheckResult result; + SourceLocation loc = Init->getLocStart(); + // Get the type before calling CheckSingleAssignmentConstraints(), since + // it can promote the expression. + QualType rhsType = Init->getType(); + + result = CheckSingleAssignmentConstraints(DeclType, Init); + + // decode the result (notice that extensions still return a type). + switch (result) { + case Compatible: + break; + case Incompatible: + Diag(loc, diag::err_typecheck_assign_incompatible, + DeclType.getAsString(), rhsType.getAsString(), + Init->getSourceRange()); + return true; + case PointerFromInt: + // check for null pointer constant (C99 6.3.2.3p3) + if (!Init->isNullPointerConstant(Context)) { + Diag(loc, diag::ext_typecheck_assign_pointer_int, + DeclType.getAsString(), rhsType.getAsString(), + Init->getSourceRange()); + return true; + } + break; + case IntFromPointer: + Diag(loc, diag::ext_typecheck_assign_pointer_int, + DeclType.getAsString(), rhsType.getAsString(), + Init->getSourceRange()); + break; + case IncompatiblePointer: + Diag(loc, diag::ext_typecheck_assign_incompatible_pointer, + DeclType.getAsString(), rhsType.getAsString(), + Init->getSourceRange()); + break; + case CompatiblePointerDiscardsQualifiers: + Diag(loc, diag::ext_typecheck_assign_discards_qualifiers, + DeclType.getAsString(), rhsType.getAsString(), + Init->getSourceRange()); + break; + } + return false; +} + +QualType Sema::CheckInitializer(Expr *Init, QualType DeclType) { + InitListExpr *InitList = dyn_cast(Init); + if (!InitList) { + return CheckSingleInitializer(Init, DeclType) ? QualType() : DeclType; + } + // We have an InitListExpr, make sure we set the type. + Init->setType(DeclType); + // FIXME: Lot of checking still to do... + return DeclType; +} + Sema::DeclTy * Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, DeclTy *lastDeclarator) { @@ -375,7 +432,10 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, } } NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator); - } else { + } else { + if (Init) { + CheckInitializer(Init, R); + } // Block scope. C99 6.7p7: If an identifier for an object is declared with // no linkage (C99 6.2.2p6), the type for the object shall be complete... if (SC != VarDecl::Extern) { @@ -410,10 +470,7 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, NewVD = MergeVarDecl(NewVD, PrevDecl); if (NewVD == 0) return 0; } - if (Init) { - AssignmentCheckResult result; - result = CheckSingleAssignmentConstraints(R, Init); - // FIXME: emit errors if appropriate. + if (Init) { // FIXME: This will likely move up above...for now, it stays. NewVD->setInit(Init); } New = NewVD; diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index daddb50c71..713ddb446d 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -642,15 +642,14 @@ ParseCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, Action::ExprResult Sema:: ParseInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit, SourceLocation RBraceLoc) { -// Expr **InitList = reinterpret_cast(initlist); + Expr **InitList = reinterpret_cast(initlist); // FIXME: add semantic analysis (C99 6.7.8). This involves // knowledge of the object being intialized. As a result, the code for // doing the semantic analysis will likely be located elsewhere (i.e. in // consumers of InitListExpr (e.g. ParseDeclarator, ParseCompoundLiteral). - //return new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc); - return false; // FIXME instantiate an InitListExpr. + return new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc); } Action::ExprResult Sema:: diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c new file mode 100644 index 0000000000..2a26103a31 --- /dev/null +++ b/test/Sema/array-init.c @@ -0,0 +1,27 @@ +// RUN: clang -parse-ast-check -pedantic %s + +void func() { + int x = 1; + + //int x2[] = { 1, 3, 5 }; + + int x3[x] = { 1, 2 }; // gcc-error {{variable-sized object may not be initialized}} + + int x4 = { 1, 2 }; // gcc-warning {{excess elements in array initializer}} + + int y[4][3] = { + { 1, 3, 5 }, + { 2, 4, 6 }, + { 3, 5, 7 }, + }; + + int y2[4][3] = { + 1, 3, 5, 2, 4, 6, 3, 5, 7 + }; + + struct threeElements { + int a,b,c; + } z = { 1 }; + + struct threeElements *p = 7; // expected-warning{{incompatible types assigning 'int' to 'struct threeElements *'}} +}