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.
llvm-svn: 41521
This commit is contained in:
parent
12687ff9b8
commit
7e6f7c25bf
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<ValueDecl>(D))
|
||||
if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
||||
ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD);
|
||||
|
||||
// FIXME: generalize this for all decls.
|
||||
if (PVD && PVD->getInvalidType())
|
||||
return true;
|
||||
return new DeclRefExpr(VD, VD->getType(), Loc);
|
||||
}
|
||||
if (isa<TypedefDecl>(D))
|
||||
return Diag(Loc, diag::err_unexpected_typedef, II.getName());
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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<DeclaratorChunk, 8> 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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue