Bug #:
Submitted by: Reviewed by: - ParseMemberReferenceExpr wasn't operating on the canonical type. From now on, I will make sure the prologue to each Parse/Check function has both the qualified type and the canonical type. - More refinements to ParseDeclarator. It was allowing variable declarations to incomplete types (e.g. void, struct foo, where foo wasn't defined). llvm-svn: 39371
This commit is contained in:
parent
95af013c77
commit
ca8f71287f
|
@ -260,17 +260,28 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
|||
TypeRef R = GetTypeForDeclarator(D, S);
|
||||
if (R.isNull()) return 0;
|
||||
|
||||
ObjectDecl::StorageClass S;
|
||||
ObjectDecl::StorageClass SC;
|
||||
switch (D.getDeclSpec().getStorageClassSpec()) {
|
||||
default: assert(0 && "Unknown storage class!");
|
||||
case 0: S = ObjectDecl::None;
|
||||
case DeclSpec::SCS_extern: S = ObjectDecl::Extern; break;
|
||||
case DeclSpec::SCS_static: S = ObjectDecl::Static; break;
|
||||
case DeclSpec::SCS_unspecified: SC = ObjectDecl::None; break;
|
||||
case DeclSpec::SCS_extern: SC = ObjectDecl::Extern; break;
|
||||
case DeclSpec::SCS_static: SC = ObjectDecl::Static; break;
|
||||
// The following 2 should never be seen in this context.
|
||||
case DeclSpec::SCS_auto: S = ObjectDecl::Auto; break;
|
||||
case DeclSpec::SCS_register: S = ObjectDecl::Register; break;
|
||||
case DeclSpec::SCS_auto: SC = ObjectDecl::Auto; break;
|
||||
case DeclSpec::SCS_register: SC = ObjectDecl::Register; break;
|
||||
}
|
||||
VarDecl *NewVD = new VarDecl(D.getIdentifierLoc(), II, R, S);
|
||||
// C99 6.9.2p3: If the declaration of an identifier for an object is a
|
||||
// tentative definition and has internal linkage, the declared type shall
|
||||
// not be an incomplete type.
|
||||
if ((S->getParent() == 0 && !Init && SC == ObjectDecl::None) ||
|
||||
SC == ObjectDecl::Static) {
|
||||
// FIXME: need a check for internal linkage.
|
||||
if (R->isIncompleteType()) {
|
||||
Diag(D.getIdentifierLoc(), diag::err_typecheck_decl_incomplete_type, R);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
VarDecl *NewVD = new VarDecl(D.getIdentifierLoc(), II, R, SC);
|
||||
|
||||
// Merge the decl with the existing one if appropriate.
|
||||
if (PrevDecl) {
|
||||
|
|
|
@ -266,20 +266,24 @@ Action::ExprResult Sema::
|
|||
ParseMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind, SourceLocation MemberLoc,
|
||||
IdentifierInfo &Member) {
|
||||
TypeRef BT = ((Expr *)Base)->getTypeRef();
|
||||
|
||||
assert(!BT.isNull() && "no type for member expression");
|
||||
TypeRef qualifiedType = ((Expr *)Base)->getTypeRef();
|
||||
|
||||
assert(!qualifiedType.isNull() && "no type for member expression");
|
||||
|
||||
Type *canonType = qualifiedType->getCanonicalType();
|
||||
|
||||
if (OpKind == tok::arrow) {
|
||||
if (PointerType *PT = dyn_cast<PointerType>(BT))
|
||||
BT = PT->getPointeeType();
|
||||
else
|
||||
if (PointerType *PT = dyn_cast<PointerType>(canonType)) {
|
||||
qualifiedType = PT->getPointeeType();
|
||||
canonType = qualifiedType->getCanonicalType();
|
||||
} else
|
||||
return Diag(OpLoc, diag::err_typecheck_member_reference_arrow);
|
||||
}
|
||||
if (isa<RecordType>(BT)) { // get the struct/union definition from the type.
|
||||
RecordDecl *RD = cast<RecordType>(BT)->getDecl();
|
||||
if (isa<RecordType>(canonType)) {
|
||||
// get the struct/union definition from the type.
|
||||
RecordDecl *RD = cast<RecordType>(canonType)->getDecl();
|
||||
|
||||
if (BT->isIncompleteType())
|
||||
if (canonType->isIncompleteType())
|
||||
return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RD->getName());
|
||||
|
||||
if (FieldDecl *MemberDecl = RD->getMember(&Member))
|
||||
|
|
|
@ -260,17 +260,28 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
|||
TypeRef R = GetTypeForDeclarator(D, S);
|
||||
if (R.isNull()) return 0;
|
||||
|
||||
ObjectDecl::StorageClass S;
|
||||
ObjectDecl::StorageClass SC;
|
||||
switch (D.getDeclSpec().getStorageClassSpec()) {
|
||||
default: assert(0 && "Unknown storage class!");
|
||||
case 0: S = ObjectDecl::None;
|
||||
case DeclSpec::SCS_extern: S = ObjectDecl::Extern; break;
|
||||
case DeclSpec::SCS_static: S = ObjectDecl::Static; break;
|
||||
case DeclSpec::SCS_unspecified: SC = ObjectDecl::None; break;
|
||||
case DeclSpec::SCS_extern: SC = ObjectDecl::Extern; break;
|
||||
case DeclSpec::SCS_static: SC = ObjectDecl::Static; break;
|
||||
// The following 2 should never be seen in this context.
|
||||
case DeclSpec::SCS_auto: S = ObjectDecl::Auto; break;
|
||||
case DeclSpec::SCS_register: S = ObjectDecl::Register; break;
|
||||
case DeclSpec::SCS_auto: SC = ObjectDecl::Auto; break;
|
||||
case DeclSpec::SCS_register: SC = ObjectDecl::Register; break;
|
||||
}
|
||||
VarDecl *NewVD = new VarDecl(D.getIdentifierLoc(), II, R, S);
|
||||
// C99 6.9.2p3: If the declaration of an identifier for an object is a
|
||||
// tentative definition and has internal linkage, the declared type shall
|
||||
// not be an incomplete type.
|
||||
if ((S->getParent() == 0 && !Init && SC == ObjectDecl::None) ||
|
||||
SC == ObjectDecl::Static) {
|
||||
// FIXME: need a check for internal linkage.
|
||||
if (R->isIncompleteType()) {
|
||||
Diag(D.getIdentifierLoc(), diag::err_typecheck_decl_incomplete_type, R);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
VarDecl *NewVD = new VarDecl(D.getIdentifierLoc(), II, R, SC);
|
||||
|
||||
// Merge the decl with the existing one if appropriate.
|
||||
if (PrevDecl) {
|
||||
|
|
|
@ -266,20 +266,24 @@ Action::ExprResult Sema::
|
|||
ParseMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind, SourceLocation MemberLoc,
|
||||
IdentifierInfo &Member) {
|
||||
TypeRef BT = ((Expr *)Base)->getTypeRef();
|
||||
|
||||
assert(!BT.isNull() && "no type for member expression");
|
||||
TypeRef qualifiedType = ((Expr *)Base)->getTypeRef();
|
||||
|
||||
assert(!qualifiedType.isNull() && "no type for member expression");
|
||||
|
||||
Type *canonType = qualifiedType->getCanonicalType();
|
||||
|
||||
if (OpKind == tok::arrow) {
|
||||
if (PointerType *PT = dyn_cast<PointerType>(BT))
|
||||
BT = PT->getPointeeType();
|
||||
else
|
||||
if (PointerType *PT = dyn_cast<PointerType>(canonType)) {
|
||||
qualifiedType = PT->getPointeeType();
|
||||
canonType = qualifiedType->getCanonicalType();
|
||||
} else
|
||||
return Diag(OpLoc, diag::err_typecheck_member_reference_arrow);
|
||||
}
|
||||
if (isa<RecordType>(BT)) { // get the struct/union definition from the type.
|
||||
RecordDecl *RD = cast<RecordType>(BT)->getDecl();
|
||||
if (isa<RecordType>(canonType)) {
|
||||
// get the struct/union definition from the type.
|
||||
RecordDecl *RD = cast<RecordType>(canonType)->getDecl();
|
||||
|
||||
if (BT->isIncompleteType())
|
||||
if (canonType->isIncompleteType())
|
||||
return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RD->getName());
|
||||
|
||||
if (FieldDecl *MemberDecl = RD->getMember(&Member))
|
||||
|
|
|
@ -504,6 +504,8 @@ DIAG(err_typecheck_not_modifiable, ERROR,
|
|||
"cannot modify read-only value of type '%s'")
|
||||
DIAG(err_typecheck_arithmetic_incomplete_type, ERROR,
|
||||
"arithmetic on pointer to incomplete type '%s'")
|
||||
DIAG(err_typecheck_decl_incomplete_type, ERROR,
|
||||
"variable has incomplete type '%s'")
|
||||
|
||||
// Statements.
|
||||
DIAG(err_continue_not_in_loop, ERROR,
|
||||
|
|
Loading…
Reference in New Issue