diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 52 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaNamedCast.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 68 |
7 files changed, 138 insertions, 53 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 40c9a99c7b2..fa4301beb6b 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -270,6 +270,11 @@ public: virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); + bool DiagnoseIncompleteType(SourceLocation Loc, QualType T, unsigned diag, + SourceRange Range1 = SourceRange(), + SourceRange Range2 = SourceRange(), + QualType PrintType = QualType()); + //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cff01c65301..fe604960f72 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -705,10 +705,9 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { // C99 6.7.5.3p4: the parameters in a parameter type list in a // function declarator that is part of a function definition of // that function shall not have incomplete type. - if (Param->getType()->isIncompleteType() && - !Param->isInvalidDecl()) { - Diag(Param->getLocation(), diag::err_typecheck_decl_incomplete_type) - << Param->getType(); + if (!Param->isInvalidDecl() && + DiagnoseIncompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); HasInvalidParm = true; } @@ -2503,10 +2502,10 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { // no linkage (C99 6.2.2p6), the type for the object shall be complete... if (IDecl->isBlockVarDecl() && IDecl->getStorageClass() != VarDecl::Extern) { - if (T->isIncompleteType() && !IDecl->isInvalidDecl()) { - Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type)<<T; + if (!IDecl->isInvalidDecl() && + DiagnoseIncompleteType(IDecl->getLocation(), T, + diag::err_typecheck_decl_incomplete_type)) IDecl->setInvalidDecl(); - } } // File scope. C99 6.9.2p2: A declaration of an identifier for and // object that has file scope without an initializer, and without a @@ -2517,13 +2516,13 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { if (T->isIncompleteArrayType()) { // C99 6.9.2 (p2, p5): Implicit initialization causes an incomplete // array to be completed. Don't issue a diagnostic. - } else if (T->isIncompleteType() && !IDecl->isInvalidDecl()) { + } else if (!IDecl->isInvalidDecl() && + DiagnoseIncompleteType(IDecl->getLocation(), T, + diag::err_typecheck_decl_incomplete_type)) // C99 6.9.2p3: If the declaration of an identifier for an object is // a tentative definition and has internal linkage (C99 6.2.2p3), the // declared type shall not be an incomplete type. - Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type)<<T; IDecl->setInvalidDecl(); - } } if (IDecl->isFileVarDecl()) CheckForFileScopedRedefinitions(S, IDecl); @@ -3382,7 +3381,8 @@ void Sema::ActOnFields(Scope* S, // C99 6.7.2.1p2 - A field may not be an incomplete type except... if (FDTy->isIncompleteType()) { if (!Record) { // Incomplete ivar type is always an error. - Diag(FD->getLocation(), diag::err_field_incomplete) <<FD->getDeclName(); + DiagnoseIncompleteType(FD->getLocation(), FD->getType(), + diag::err_field_incomplete); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; @@ -3390,7 +3390,8 @@ void Sema::ActOnFields(Scope* S, if (i != NumFields-1 || // ... that the last member ... !Record->isStruct() || // ... of a structure ... !FDTy->isArrayType()) { //... may have incomplete array type. - Diag(FD->getLocation(), diag::err_field_incomplete) <<FD->getDeclName(); + DiagnoseIncompleteType(FD->getLocation(), FD->getType(), + diag::err_field_incomplete); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 33a31c7500d..95f920063d2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -339,8 +339,9 @@ Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, // C++ [class.derived]p2: // The class-name in a base-specifier shall not be an incompletely // defined class. - if (BaseType->isIncompleteType()) - return Diag(BaseLoc, diag::err_incomplete_base_class) << SpecifierRange; + if (DiagnoseIncompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class, + SpecifierRange)) + return true; // If the base class is polymorphic, the new one is, too. RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl(); @@ -2179,17 +2180,19 @@ Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) // incomplete type, other than [cv] void*. QualType BaseType = ExDeclType; int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference + unsigned DK = diag::err_catch_incomplete; if (const PointerType *Ptr = BaseType->getAsPointerType()) { BaseType = Ptr->getPointeeType(); Mode = 1; + DK = diag::err_catch_incomplete_ptr; } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) { BaseType = Ref->getPointeeType(); Mode = 2; + DK = diag::err_catch_incomplete_ref; } - if ((Mode == 0 || !BaseType->isVoidType()) && BaseType->isIncompleteType()) { + if ((Mode == 0 || !BaseType->isVoidType()) && + DiagnoseIncompleteType(Begin, BaseType, DK)) Invalid = true; - Diag(Begin, diag::err_catch_incomplete) << BaseType << Mode; - } // FIXME: Need to test for ability to copy-construct and destroy the // exception variable. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index be87ee9c496..fb83cabd2df 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1021,10 +1021,11 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, else if (exprType->isVoidType()) Diag(OpLoc, diag::ext_sizeof_void_type) << (isSizeof ? "sizeof" : "__alignof") << ExprRange; - else if (exprType->isIncompleteType()) - return Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : - diag::err_alignof_incomplete_type) - << exprType << ExprRange; + else + return DiagnoseIncompleteType(OpLoc, exprType, + isSizeof ? diag::err_sizeof_incomplete_type : + diag::err_alignof_incomplete_type, + ExprRange); return false; } @@ -1466,9 +1467,11 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAsRecordType()) { RecordDecl *RDecl = RTy->getDecl(); - if (RTy->isIncompleteType()) - return ExprError(Diag(OpLoc, diag::err_typecheck_incomplete_tag) - << RDecl->getDeclName() << BaseExpr->getSourceRange()); + if (DiagnoseIncompleteType(OpLoc, BaseType, + diag::err_typecheck_incomplete_tag, + BaseExpr->getSourceRange())) + return ExprError(); + // The record definition is complete, now make sure the member is valid. // FIXME: Qualified name lookup for C++ is a bit more complicated // than this. @@ -1906,11 +1909,10 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, if (literalType->isVariableArrayType()) return Diag(LParenLoc, diag::err_variable_object_no_init) << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()); - } else if (literalType->isIncompleteType()) { - return Diag(LParenLoc, diag::err_typecheck_decl_incomplete_type) - << literalType - << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()); - } + } else if (DiagnoseIncompleteType(LParenLoc, literalType, + diag::err_typecheck_decl_incomplete_type, + SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()))) + return true; if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, DeclarationName(), /*FIXME:DirectInit=*/false)) @@ -2643,10 +2645,16 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 if (PTy->getPointeeType()->isVoidType()) { Diag(Loc, diag::ext_gnu_void_ptr) << lex->getSourceRange() << rex->getSourceRange(); - } else { - Diag(Loc, diag::err_typecheck_arithmetic_incomplete_type) + } else if (PTy->getPointeeType()->isFunctionType()) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) << lex->getType() << lex->getSourceRange(); return QualType(); + } else { + DiagnoseIncompleteType(Loc, PTy->getPointeeType(), + diag::err_typecheck_arithmetic_incomplete_type, + lex->getSourceRange(), SourceRange(), + lex->getType()); + return QualType(); } } return PExp->getType(); @@ -3038,9 +3046,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { break; case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: - Diag = diag::err_typecheck_incomplete_type_not_modifiable_lvalue; - NeedType = true; - break; + return S.DiagnoseIncompleteType(Loc, E->getType(), + diag::err_typecheck_incomplete_type_not_modifiable_lvalue, + E->getSourceRange()); case Expr::MLV_DuplicateVectorComponents: Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue; break; @@ -3155,10 +3163,16 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, } else if (PT->getPointeeType()->isVoidType()) { // Pointer to void is extension. Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); - } else { - Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type) + } else if (PT->getPointeeType()->isFunctionType()) { + Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) << ResType << Op->getSourceRange(); return QualType(); + } else { + DiagnoseIncompleteType(OpLoc, PT->getPointeeType(), + diag::err_typecheck_arithmetic_incomplete_type, + Op->getSourceRange(), SourceRange(), + ResType); + return QualType(); } } else if (ResType->isComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 09db18ea541..8958221ef55 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -172,9 +172,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // if (Ty->isArrayType()) return Diag(TyBeginLoc, diag::err_value_init_for_array_type) << FullRange; - if (!Ty->isDependentType() && Ty->isIncompleteType() && !Ty->isVoidType()) - return Diag(TyBeginLoc, diag::err_invalid_incomplete_type_use) - << Ty << FullRange; + if (!Ty->isDependentType() && !Ty->isVoidType() && + DiagnoseIncompleteType(TyBeginLoc, Ty, + diag::err_invalid_incomplete_type_use, FullRange)) + return true; return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc); } @@ -578,9 +579,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } QualType Pointee = Type->getAsPointerType()->getPointeeType(); - if (Pointee->isIncompleteType() && !Pointee->isVoidType()) - Diag(StartLoc, diag::warn_delete_incomplete) - << Pointee << Ex->getSourceRange(); + if (!Pointee->isVoidType() && + DiagnoseIncompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, + Ex->getSourceRange())) + return true; else if (!Pointee->isObjectType()) { Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange(); diff --git a/clang/lib/Sema/SemaNamedCast.cpp b/clang/lib/Sema/SemaNamedCast.cpp index 3d3572d00ce..06fc9d83bad 100644 --- a/clang/lib/Sema/SemaNamedCast.cpp +++ b/clang/lib/Sema/SemaNamedCast.cpp @@ -685,11 +685,10 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, if (DestPointee->isVoidType()) { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { - if (!DestRecord->getDecl()->isDefinition()) { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_incomplete) - << DestPointee.getUnqualifiedType() << DestRange; + if (Self.DiagnoseIncompleteType(OpRange.getBegin(), DestPointee, + diag::err_bad_dynamic_cast_incomplete, + DestRange)) return; - } } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << DestPointee.getUnqualifiedType() << DestRange; @@ -720,11 +719,10 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const RecordType *SrcRecord = SrcPointee->getAsRecordType(); if (SrcRecord) { - if (!SrcRecord->getDecl()->isDefinition()) { - Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_incomplete) - << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + if (Self.DiagnoseIncompleteType(OpRange.getBegin(), SrcPointee, + diag::err_bad_dynamic_cast_incomplete, + SrcExpr->getSourceRange())) return; - } } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8a459f4d3ea..ecae79320dd 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -352,9 +352,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (T->isIncompleteType()) { - Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_incomplete_type) - << T; + if (DiagnoseIncompleteType(D.getIdentifierLoc(), T, + diag::err_illegal_decl_array_incomplete_type)) { T = Context.IntTy; D.setInvalidType(true); } else if (T->isFunctionType()) { @@ -690,4 +689,67 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { } } +/// @brief If the type T is incomplete and cannot be completed, +/// produce a suitable diagnostic. +/// +/// This routine checks whether the type @p T is complete in any +/// context where a complete type is required. If @p T is a complete +/// type, returns false. If @p T is incomplete, issues the diagnostic +/// @p diag (giving it the type @p T) and returns true. +/// +/// @param Loc The location in the source that the incomplete type +/// diagnostic should refer to. +/// +/// @param T The type that this routine is examining for completeness. +/// +/// @param diag The diagnostic value (e.g., +/// @c diag::err_typecheck_decl_incomplete_type) that will be used +/// for the error message if @p T is incomplete. +/// +/// @param Range1 An optional range in the source code that will be a +/// part of the "incomplete type" error message. +/// +/// @param Range2 An optional range in the source code that will be a +/// part of the "incomplete type" error message. +/// +/// @param PrintType If non-NULL, the type that should be printed +/// instead of @p T. This parameter should be used when the type that +/// we're checking for incompleteness isn't the type that should be +/// displayed to the user, e.g., when T is a type and PrintType is a +/// pointer to T. +/// +/// @returns @c true if @p T is incomplete and a diagnostic was emitted, +/// @c false otherwise. +/// +/// @todo When Clang gets proper support for C++ templates, this +/// routine will also be able perform template instantiation when @p T +/// is a class template specialization. +bool Sema::DiagnoseIncompleteType(SourceLocation Loc, QualType T, unsigned diag, + SourceRange Range1, SourceRange Range2, + QualType PrintType) { + // If we have a complete type, we're done. + if (!T->isIncompleteType()) + return false; + + if (PrintType.isNull()) + PrintType = T; + + // We have an incomplete type. Produce a diagnostic. + Diag(Loc, diag) << PrintType << Range1 << Range2; + // If the type was a forward declaration of a class/struct/union + // type, produce + const TagType *Tag = 0; + if (const RecordType *Record = T->getAsRecordType()) + Tag = Record; + else if (const EnumType *Enum = T->getAsEnumType()) + Tag = Enum; + + if (Tag && !Tag->getDecl()->isInvalidDecl()) + Diag(Tag->getDecl()->getLocation(), + Tag->isBeingDefined() ? diag::note_type_being_defined + : diag::note_forward_declaration) + << QualType(Tag, 0); + + return true; +} |