From: Steve Naroff Date: Tue, 28 Aug 2007 03:03:08 +0000 (+0000) Subject: Implement more thoughful error recovery when dealing with bogus declarator types. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e1223f7246c2c297f7b62816fd8c6a0a14151977;p=clang Implement more thoughful error recovery when dealing with bogus declarator types. For example, the following code was resulting in spurious warnings. This was the result of Sema::GetTypeForDeclarator() synthesizing a type to hand back to the caller (in this case, "int []", instead of "struct s[]", which is invalid). struct s; struct s* t (struct s z[]) { // expected-error {{array has incomplete element type}} return z; } Strategy: Flag the error in Declarator/DeclaratorChunk. This info is later stored in the ParmVarDecl. If the decl is referenced, Sema::ParseIdentifierExpr() will check if the type is invalid. If so, it quietly returns "true", without instantiating a DeclRefExpr. This seems to work nicely. If Chris is happy with the approach, I will generalize this to all VarDecls. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41521 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp index 8a03184178..9ac5f5f891 100644 --- a/Parse/ParseDecl.cpp +++ b/Parse/ParseDecl.cpp @@ -1332,9 +1332,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { ParmII = 0; } - ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), - ParamTy.Val)); + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType())); // If the next token is a comma, consume it and keep reading arguments. if (Tok.getKind() != tok::comma) break; diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index be61d735d7..43d2ca9ec1 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -463,7 +463,8 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { } return NewGroup; } - + +// Called from Sema::ParseStartOfFunctionDef(). ParmVarDecl * Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo, Scope *FnScope) { @@ -505,7 +506,7 @@ Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo, parmDeclType = Context.getPointerType(parmDeclType); ParmVarDecl *New = new ParmVarDecl(PI.IdentLoc, II, parmDeclType, - VarDecl::None, 0); + VarDecl::None, 0, PI.InvalidType); // If this has an identifier, add it to the scope stack. if (II) { diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index b715556ce2..88a057930b 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -74,8 +74,14 @@ Sema::ExprResult Sema::ParseIdentifierExpr(Scope *S, SourceLocation Loc, return Diag(Loc, diag::err_undeclared_var_use, II.getName()); } } - if (ValueDecl *VD = dyn_cast(D)) + if (ValueDecl *VD = dyn_cast(D)) { + ParmVarDecl *PVD = dyn_cast(VD); + + // FIXME: generalize this for all decls. + if (PVD && PVD->getInvalidType()) + return true; return new DeclRefExpr(VD, VD->getType(), Loc); + } if (isa(D)) return Diag(Loc, diag::err_unexpected_typedef, II.getName()); diff --git a/Sema/SemaType.cpp b/Sema/SemaType.cpp index 535b079626..17ab64a196 100644 --- a/Sema/SemaType.cpp +++ b/Sema/SemaType.cpp @@ -123,7 +123,7 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) { /// instances. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { QualType T = ConvertDeclSpecToType(D.getDeclSpec(), Context); - + // Apply const/volatile/restrict qualifiers to T. T = T.getQualifiedType(D.getDeclSpec().getTypeQualifiers()); @@ -138,6 +138,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { // C++ 8.3.2p4: There shall be no ... pointers to references ... Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference, D.getIdentifier()->getName()); + D.setInvalidType(true); T = Context.IntTy; } @@ -150,6 +151,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { Diag(D.getIdentifierLoc(), diag::err_illegal_decl_reference_to_reference, D.getIdentifier()->getName()); + D.setInvalidType(true); T = RT->getReferenceeType(); } @@ -170,19 +172,27 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { if (T->isIncompleteType()) { Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_incomplete_type, T.getAsString()); + T = Context.IntTy; + D.setInvalidType(true); } else if (T->isFunctionType()) { Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions, D.getIdentifier()->getName()); + T = Context.getPointerType(T); + D.setInvalidType(true); } else if (const ReferenceType *RT = T->getAsReferenceType()) { // C++ 8.3.2p4: There shall be no ... arrays of references ... Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references, D.getIdentifier()->getName()); + T = RT->getReferenceeType(); + D.setInvalidType(true); } else if (const RecordType *EltTy = T->getAsRecordType()) { // If the element type is a struct or union that contains a variadic // array, reject it: C99 6.7.2.1p2. if (EltTy->getDecl()->hasFlexibleArrayMember()) { Diag(DeclType.Loc, diag::err_flexible_array_in_array, T.getAsString()); + T = Context.IntTy; + D.setInvalidType(true); } } T = Context.getArrayType(T, ASM, ATI.TypeQuals, @@ -264,6 +274,7 @@ Sema::TypeResult Sema::ParseTypeName(Scope *S, Declarator &D) { return T.getAsOpaquePtr(); } +// Called from Parser::ParseParenDeclarator(). Sema::TypeResult Sema::ParseParamDeclaratorType(Scope *S, Declarator &D) { // Note: parameters have identifiers, but we don't care about them here, we // just want the type converted. diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 68d35f10d2..1ffcb171de 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -221,11 +221,14 @@ public: /// ParmVarDecl - Represent a parameter to a function. class ParmVarDecl : public VarDecl { + bool InvalidType; public: ParmVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S, - Decl *PrevDecl) - : VarDecl(ParmVariable, L, Id, T, S, PrevDecl) {} + Decl *PrevDecl, bool flag) + : VarDecl(ParmVariable, L, Id, T, S, PrevDecl), InvalidType(flag) {} + bool getInvalidType() const { return InvalidType; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == ParmVariable; } static bool classof(const ParmVarDecl *D) { return true; } diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index aec81dac2f..c0956dc00f 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -315,10 +315,12 @@ struct DeclaratorChunk { IdentifierInfo *Ident; SourceLocation IdentLoc; Action::TypeTy *TypeInfo; + bool InvalidType; // FIXME: this also needs an attribute list. ParamInfo() {} - ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::TypeTy *typ) - : Ident(ident), IdentLoc(iloc), TypeInfo(typ) { + ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::TypeTy *typ, + bool flag = false) + : Ident(ident), IdentLoc(iloc), TypeInfo(typ), InvalidType(flag) { } }; @@ -447,11 +449,14 @@ private: /// DeclTypeInfo.back() will be the least closely bound. llvm::SmallVector DeclTypeInfo; + // InvalidType - Set by Sema::GetTypeForDeclarator(). + bool InvalidType; + // attributes. - AttributeList *AttrList; + AttributeList *AttrList; public: Declarator(const DeclSpec &ds, TheContext C) - : DS(ds), Identifier(0), Context(C), AttrList(0) { + : DS(ds), Identifier(0), Context(C), InvalidType(false), AttrList(0) { } ~Declarator() { @@ -552,6 +557,9 @@ public: AttrList = alist; } AttributeList *getAttributes() const { return AttrList; } + + void setInvalidType(bool flag) { InvalidType = flag; } + bool getInvalidType() { return InvalidType; } };