From ca8f71287f9031a48c58d49ee84a6511fcd15730 Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Sun, 1 Apr 2007 01:41:35 +0000 Subject: [PATCH] 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 --- clang/AST/SemaDecl.cpp | 25 +++++++++++++------ clang/AST/SemaExpr.cpp | 22 +++++++++------- clang/Sema/SemaDecl.cpp | 25 +++++++++++++------ clang/Sema/SemaExpr.cpp | 22 +++++++++------- clang/include/clang/Basic/DiagnosticKinds.def | 2 ++ 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/clang/AST/SemaDecl.cpp b/clang/AST/SemaDecl.cpp index 8a3d8ec186b0..18f1cfaa06f8 100644 --- a/clang/AST/SemaDecl.cpp +++ b/clang/AST/SemaDecl.cpp @@ -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) { diff --git a/clang/AST/SemaExpr.cpp b/clang/AST/SemaExpr.cpp index 9038a2641250..8437545c0c94 100644 --- a/clang/AST/SemaExpr.cpp +++ b/clang/AST/SemaExpr.cpp @@ -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(BT)) - BT = PT->getPointeeType(); - else + if (PointerType *PT = dyn_cast(canonType)) { + qualifiedType = PT->getPointeeType(); + canonType = qualifiedType->getCanonicalType(); + } else return Diag(OpLoc, diag::err_typecheck_member_reference_arrow); } - if (isa(BT)) { // get the struct/union definition from the type. - RecordDecl *RD = cast(BT)->getDecl(); + if (isa(canonType)) { + // get the struct/union definition from the type. + RecordDecl *RD = cast(canonType)->getDecl(); - if (BT->isIncompleteType()) + if (canonType->isIncompleteType()) return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RD->getName()); if (FieldDecl *MemberDecl = RD->getMember(&Member)) diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index 8a3d8ec186b0..18f1cfaa06f8 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -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) { diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index 9038a2641250..8437545c0c94 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -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(BT)) - BT = PT->getPointeeType(); - else + if (PointerType *PT = dyn_cast(canonType)) { + qualifiedType = PT->getPointeeType(); + canonType = qualifiedType->getCanonicalType(); + } else return Diag(OpLoc, diag::err_typecheck_member_reference_arrow); } - if (isa(BT)) { // get the struct/union definition from the type. - RecordDecl *RD = cast(BT)->getDecl(); + if (isa(canonType)) { + // get the struct/union definition from the type. + RecordDecl *RD = cast(canonType)->getDecl(); - if (BT->isIncompleteType()) + if (canonType->isIncompleteType()) return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RD->getName()); if (FieldDecl *MemberDecl = RD->getMember(&Member)) diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 436206e7d263..44de03889d4d 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -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,