diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-24 19:52:54 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-24 19:52:54 +0000 |
commit | e7450f5dbd5bed63b8ef9db86350a8fc3db011e8 (patch) | |
tree | 61d7b8565db05760fb505fa9c25af4ed13e48bbf | |
parent | 6256d3654533547a7996170647c21a859cb441e1 (diff) |
Make sure to use RequireCompleteType rather than testing for
incomplete types. RequireCompleteType is needed when the type may be
completed by instantiating a template.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67643 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 65 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 171 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 41 | ||||
-rw-r--r-- | test/Sema/function.c | 3 | ||||
-rw-r--r-- | test/Sema/typecheck-binop.c | 6 | ||||
-rw-r--r-- | test/SemaCXX/member-pointer.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/new-delete.cpp | 5 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-complete.cpp | 47 |
9 files changed, 225 insertions, 138 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7543a7d768..daf1d9cdb3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -817,7 +817,7 @@ def err_block_return_missing_expr : Error< def err_block_with_return_type_requires_args : Error< "block with explicit return type requires argument list">; def err_func_def_incomplete_result : Error< - "result type for function definition cannot be incomplete">; + "incomplete result type %0 in function definition">; // Expressions. def ext_sizeof_function_type : Extension< @@ -842,8 +842,10 @@ def warn_floatingpoint_eq : Warning< def err_typecheck_subscript_value : Error< "subscripted value is neither array nor pointer">; def err_typecheck_subscript : Error<"array subscript is not an integer">; -def err_typecheck_subscript_not_object : Error< - "illegal subscript of non-object type %0">; +def err_subscript_function_type : Error< + "subscript of pointer to function type %0">; +def err_subscript_incomplete_type : Error< + "subscript of pointer to incomplete type %0">; def err_typecheck_member_reference_struct_union : Error< "member reference base type %0 is not a structure or union">; def err_typecheck_member_reference_ivar : Error< @@ -1026,7 +1028,9 @@ def err_static_illegal_in_new : Error< def err_array_new_needs_size : Error< "array size must be specified in new expressions">; def err_bad_new_type : Error< - "cannot allocate %select{function|incomplete|reference}1 type %0 with new">; + "cannot allocate %select{function|reference}1 type %0 with new">; +def err_new_incomplete_type : Error< + "allocation of incomplete type %0">; def err_new_array_nonconst : Error< "only the first dimension of an allocated array may be non-const">; def err_array_size_not_integral : Error< @@ -1049,8 +1053,9 @@ def err_qualified_catch_declarator : Error< "exception declarator cannot be qualified">; def err_early_catch_all : Error<"catch-all handler must come last">; def err_bad_memptr_rhs : Error< - "right hand operand to %0 must be a pointer to member of a complete class " - "but is %1">; + "right hand operand to %0 has non pointer-to-member type %1">; +def err_memptr_rhs_incomplete : Error< + "right hand operand is a pointer to member of incomplete type %0">; def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a3b60047d6..b76126aa8f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -881,6 +881,8 @@ 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. + // + // This is also C++ [dcl.fct]p6. if (!Param->isInvalidDecl() && RequireCompleteType(Param->getLocation(), Param->getType(), diag::err_typecheck_decl_incomplete_type)) { @@ -2723,12 +2725,12 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { } // The return type of a function definition must be complete - // (C99 6.9.1p3) - if (FD->getResultType()->isIncompleteType() && - !FD->getResultType()->isVoidType()) { - Diag(FD->getLocation(), diag::err_func_def_incomplete_result) << FD; + // (C99 6.9.1p3, C++ [dcl.fct]p6). + QualType ResultType = FD->getResultType(); + if (!ResultType->isDependentType() && !ResultType->isVoidType() && + RequireCompleteType(FD->getLocation(), ResultType, + diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); - } PushDeclContext(FnBodyScope, FD); @@ -3726,33 +3728,27 @@ void Sema::ActOnFields(Scope* S, if (FD->isInvalidDecl()) continue; - // C99 6.7.2.1p2 - A field may not be a function type. + // C99 6.7.2.1p2: + // A structure or union shall not contain a member with + // incomplete or function type (hence, a structure shall not + // contain an instance of itself, but may contain a pointer to + // an instance of itself), except that the last member of a + // structure with more than one named member may have incomplete + // array type; such a structure (and any union containing, + // possibly recursively, a member that is such a structure) + // shall not be a member of a structure or an element of an + // array. if (FDTy->isFunctionType()) { + // Field declared as a function. Diag(FD->getLocation(), diag::err_field_declared_as_function) << FD->getDeclName(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } - // 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. - RequireCompleteType(FD->getLocation(), FD->getType(), - diag::err_field_incomplete); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - if (i != NumFields-1 || // ... that the last member ... - !Record->isStruct() || // ... of a structure ... - !FDTy->isArrayType()) { //... may have incomplete array type. - RequireCompleteType(FD->getLocation(), FD->getType(), - diag::err_field_incomplete); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - if (NumNamedMembers < 1) { //... must have more than named member ... + } else if (FDTy->isIncompleteArrayType() && i == NumFields - 1 && + Record && Record->isStruct()) { + // Flexible array member. + if (NumNamedMembers < 1) { Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) << FD->getDeclName(); FD->setInvalidDecl(); @@ -3762,10 +3758,14 @@ void Sema::ActOnFields(Scope* S, // Okay, we have a legal flexible array member at the end of the struct. if (Record) Record->setHasFlexibleArrayMember(true); - } - /// C99 6.7.2.1p2 - a struct ending in a flexible array member cannot be the - /// field of another structure or the element of an array. - if (const RecordType *FDTTy = FDTy->getAsRecordType()) { + } else if (!FDTy->isDependentType() && + RequireCompleteType(FD->getLocation(), FD->getType(), + diag::err_field_incomplete)) { + // Incomplete type + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } else if (const RecordType *FDTTy = FDTy->getAsRecordType()) { if (FDTTy->getDecl()->hasFlexibleArrayMember()) { // If this is a member of a union, then entire union becomes "flexible". if (Record && Record->isUnion()) { @@ -3787,9 +3787,8 @@ void Sema::ActOnFields(Scope* S, } } } - } - /// A field cannot be an Objective-c object - if (FDTy->isObjCInterfaceType()) { + } else if (FDTy->isObjCInterfaceType()) { + /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2732a54e65..03d8501245 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1593,14 +1593,20 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, return ExprError(Diag(IndexExpr->getLocStart(), diag::err_typecheck_subscript) << IndexExpr->getSourceRange()); - // C99 6.5.2.1p1: "shall have type "pointer to *object* type". In practice, - // the following check catches trying to index a pointer to a function (e.g. - // void (*)(int)) and pointers to incomplete types. Functions are not - // objects in C99. - if (!ResultType->isObjectType() && !ResultType->isDependentType()) - return ExprError(Diag(BaseExpr->getLocStart(), - diag::err_typecheck_subscript_not_object) - << BaseExpr->getType() << BaseExpr->getSourceRange()); + // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, + // C++ [expr.sub]p1: The type "T" shall be a completely-defined object + // type. Note that Functions are not objects, and that (in C99 parlance) + // incomplete types are not object types. + if (ResultType->isFunctionType()) { + Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type) + << ResultType << BaseExpr->getSourceRange(); + return ExprError(); + } + if (!ResultType->isDependentType() && + RequireCompleteType(BaseExpr->getLocStart(), ResultType, + diag::err_subscript_incomplete_type, + BaseExpr->getSourceRange())) + return ExprError(); Base.release(); Idx.release(); @@ -3155,35 +3161,33 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 if (const PointerType* PTy = PExp->getType()->getAsPointerType()) { if (IExp->getType()->isIntegerType()) { // Check for arithmetic on pointers to incomplete types - if (!PTy->getPointeeType()->isObjectType()) { - if (PTy->getPointeeType()->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex->getSourceRange() << rex->getSourceRange(); - return QualType(); - } - - // GNU extension: arithmetic on pointer to void - Diag(Loc, diag::ext_gnu_void_ptr) + if (PTy->getPointeeType()->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) << lex->getSourceRange() << rex->getSourceRange(); - } else if (PTy->getPointeeType()->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex->getType() << lex->getSourceRange(); - return QualType(); - } + return QualType(); + } - // GNU extension: arithmetic on pointer to function - Diag(Loc, diag::ext_gnu_ptr_func_arith) + // GNU extension: arithmetic on pointer to void + Diag(Loc, diag::ext_gnu_void_ptr) + << lex->getSourceRange() << rex->getSourceRange(); + } else if (PTy->getPointeeType()->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) << lex->getType() << lex->getSourceRange(); - } else { - RequireCompleteType(Loc, PTy->getPointeeType(), - diag::err_typecheck_arithmetic_incomplete_type, - lex->getSourceRange(), SourceRange(), - lex->getType()); return QualType(); } - } + + // GNU extension: arithmetic on pointer to function + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << lex->getType() << lex->getSourceRange(); + } else if (!PTy->isDependentType() && + RequireCompleteType(Loc, PTy->getPointeeType(), + diag::err_typecheck_arithmetic_incomplete_type, + lex->getSourceRange(), SourceRange(), + lex->getType())) + return QualType(); + return PExp->getType(); } } @@ -3209,61 +3213,80 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { QualType lpointee = LHSPTy->getPointeeType(); - // The LHS must be an object type, not incomplete, function, etc. - if (!lpointee->isObjectType()) { - // Handle the GNU void* extension. - if (lpointee->isVoidType()) { - Diag(Loc, diag::ext_gnu_void_ptr) + // The LHS must be an completely-defined object type. + + bool ComplainAboutVoid = false; + Expr *ComplainAboutFunc = 0; + if (lpointee->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) << lex->getSourceRange() << rex->getSourceRange(); - } else if (lpointee->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex->getType() << lex->getSourceRange(); - return QualType(); - } + return QualType(); + } - // GNU extension: arithmetic on pointer to function - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << lex->getType() << lex->getSourceRange(); - } else { - Diag(Loc, diag::err_typecheck_sub_ptr_object) + // GNU C extension: arithmetic on pointer to void + ComplainAboutVoid = true; + } else if (lpointee->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) << lex->getType() << lex->getSourceRange(); return QualType(); } - } + + // GNU C extension: arithmetic on pointer to function + ComplainAboutFunc = lex; + } else if (!lpointee->isDependentType() && + RequireCompleteType(Loc, lpointee, + diag::err_typecheck_sub_ptr_object, + lex->getSourceRange(), + SourceRange(), + lex->getType())) + return QualType(); // The result type of a pointer-int computation is the pointer type. - if (rex->getType()->isIntegerType()) + if (rex->getType()->isIntegerType()) { + if (ComplainAboutVoid) + Diag(Loc, diag::ext_gnu_void_ptr) + << lex->getSourceRange() << rex->getSourceRange(); + if (ComplainAboutFunc) + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << ComplainAboutFunc->getType() + << ComplainAboutFunc->getSourceRange(); + return lex->getType(); + } // Handle pointer-pointer subtractions. if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) { QualType rpointee = RHSPTy->getPointeeType(); - // RHS must be an object type, unless void (GNU). - if (!rpointee->isObjectType()) { - // Handle the GNU void* extension. - if (rpointee->isVoidType()) { - if (!lpointee->isVoidType()) - Diag(Loc, diag::ext_gnu_void_ptr) - << lex->getSourceRange() << rex->getSourceRange(); - } else if (rpointee->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << rex->getType() << rex->getSourceRange(); - return QualType(); - } + // RHS must be a completely-type object type. + // Handle the GNU void* extension. + if (rpointee->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } - // GNU extension: arithmetic on pointer to function - if (!lpointee->isFunctionType()) - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << lex->getType() << lex->getSourceRange(); - } else { - Diag(Loc, diag::err_typecheck_sub_ptr_object) + ComplainAboutVoid = true; + } else if (rpointee->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) << rex->getType() << rex->getSourceRange(); return QualType(); } - } + + // GNU extension: arithmetic on pointer to function + if (!ComplainAboutFunc) + ComplainAboutFunc = rex; + } else if (!rpointee->isDependentType() && + RequireCompleteType(Loc, rpointee, + diag::err_typecheck_sub_ptr_object, + rex->getSourceRange(), + SourceRange(), + rex->getType())) + return QualType(); // Pointee types must be compatible. if (!Context.typesAreCompatible( @@ -3275,6 +3298,14 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, return QualType(); } + if (ComplainAboutVoid) + Diag(Loc, diag::ext_gnu_void_ptr) + << lex->getSourceRange() << rex->getSourceRange(); + if (ComplainAboutFunc) + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << ComplainAboutFunc->getType() + << ComplainAboutFunc->getSourceRange(); + return Context.getPointerDiffType(); } } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 2abf87b23f..e2cda9dff9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -242,10 +242,6 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (CheckAllocatedType(AllocType, D)) return ExprError(); - if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType, - diag::err_allocation_of_abstract_type)) - return ExprError(); - QualType ResultType = AllocType->isDependentType() ? Context.DependentTy : Context.getPointerType(AllocType); @@ -364,23 +360,20 @@ bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. - // FIXME: We don't have abstract types yet. - // FIXME: Under C++ semantics, an incomplete object type is still an object - // type. This code assumes the C semantics, where it's not. - if (!AllocType->isObjectType()) { - unsigned type; // For the select in the message. - if (AllocType->isFunctionType()) { - type = 0; - } else if(AllocType->isIncompleteType()) { - type = 1; - } else { - assert(AllocType->isReferenceType() && "Unhandled non-object type."); - type = 2; - } - Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) - << AllocType << type << D.getSourceRange(); + if (AllocType->isFunctionType()) + return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) + << AllocType << 0 << D.getSourceRange(); + else if (AllocType->isReferenceType()) + return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) + << AllocType << 1 << D.getSourceRange(); + else if (!AllocType->isDependentType() && + RequireCompleteType(D.getSourceRange().getBegin(), AllocType, + diag::err_new_incomplete_type, + D.getSourceRange())) + return true; + else if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType, + diag::err_allocation_of_abstract_type)) return true; - } // Every dimension shall be of constant size. unsigned i = 1; @@ -943,11 +936,15 @@ QualType Sema::CheckPointerToMemberOperands( // class type) [...] QualType RType = rex->getType(); const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); - if (!MemPtr || MemPtr->getClass()->isIncompleteType()) { + if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RType << rex->getSourceRange(); return QualType(); - } + } else if (RequireCompleteType(Loc, QualType(MemPtr->getClass(), 0), + diag::err_memptr_rhs_incomplete, + rex->getSourceRange())) + return QualType(); + QualType Class(MemPtr->getClass(), 0); // C++ 5.5p2 diff --git a/test/Sema/function.c b/test/Sema/function.c index c240896adf..aec76a26eb 100644 --- a/test/Sema/function.c +++ b/test/Sema/function.c @@ -59,4 +59,5 @@ void f1static() { register void f2register(int); // expected-error{{illegal storage class on function}} } -struct incomplete_test a(void) {} // expected-error{{result type for function definition cannot be incomplete}} +struct incomplete_test a(void) {} // expected-error{{incomplete result type 'struct incomplete_test' in function definition}} \ + // expected-note{{forward declaration of 'struct incomplete_test'}} diff --git a/test/Sema/typecheck-binop.c b/test/Sema/typecheck-binop.c index 496bdd3b0f..f5bdcbb70e 100644 --- a/test/Sema/typecheck-binop.c +++ b/test/Sema/typecheck-binop.c @@ -1,6 +1,6 @@ /* RUN: clang-cc %s -fsyntax-only -pedantic -verify */ -struct incomplete; +struct incomplete; // expected-note{{forward declaration of 'struct incomplete'}} int sub1(int *a, double *b) { return a - b; /* expected-error{{not pointers to compatible types}} */ @@ -18,6 +18,10 @@ int sub4(void *P, void *Q) { return P-Q; /* expected-warning{{GNU void* extension}} */ } +int sub5(void *P, int *Q) { + return P-Q; /* expected-error{{not pointers to compatible types}} */ +} + int logicaland1(int a) { return a && (void)a; /* expected-error{{invalid operands}} */ } diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index daee25533f..11993a1d4b 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -80,7 +80,7 @@ void g() { void (HasMembers::*pmd)() = &HasMembers::d; } -struct Incomplete; +struct Incomplete; // expected-note{{forward declaration}} void h() { HasMembers hm, *phm = &hm; @@ -110,12 +110,12 @@ void h() { (void)(f.*pai); // expected-error {{left hand operand to .* must be a class compatible with the right hand operand, but is 'struct F'}} (void)(ptrf->*pai); // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct F *'}} - (void)(hm.*i); // expected-error {{right hand operand to .* must be a pointer to member of a complete class but is 'int'}} - (void)(phm->*i); // expected-error {{right hand operand to ->* must be a pointer to member of a complete class but is 'int'}} + (void)(hm.*i); // expected-error {{pointer-to-member}} + (void)(phm->*i); // expected-error {{pointer-to-member}} Incomplete *inc; int Incomplete::*pii = 0; - (void)inc->*pii; // expected-error {{right hand operand to ->* must be a pointer to member of a complete class but is 'int struct Incomplete::*'}} + (void)inc->*pii; // expected-error {{right hand operand is a pointer to member of incomplete type 'struct Incomplete'}} } struct OverloadsPtrMem diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 5037a8d324..6fbf2c1386 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -41,6 +41,10 @@ void good_news() //V *pv = new (ps) V; } +struct abstract { + virtual ~abstract() = 0; +}; + void bad_news(int *ip) { int i = 1; @@ -66,7 +70,6 @@ void bad_news(int *ip) (void)::new ((S*)0) U; // expected-error {{no matching function for call to 'operator new'}} (void)new (int[]); // expected-error {{array size must be specified in new expressions}} (void)new int&; // expected-error {{cannot allocate reference type 'int &' with new}} - (void)new (void ()); // expected-error {{cannot allocate function type 'void (void)' with new}} // Some lacking cases due to lack of sema support. } diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp new file mode 100644 index 0000000000..7b4373538d --- /dev/null +++ b/test/SemaTemplate/instantiate-complete.cpp @@ -0,0 +1,47 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Tests various places where requiring a complete type involves +// instantiation of that type. + +template<typename T> +struct X { + X(T); + + T f; // expected-error{{data member instantiated with function type 'float (int)'}} \ + // expected-error{{data member instantiated with function type 'int (int)'}} \ + // expected-error{{data member instantiated with function type 'char (char)'}} \ + // expected-error{{data member instantiated with function type 'short (short)'}} \ + // expected-error{{data member instantiated with function type 'float (float)'}} \ + // expected-error{{data member instantiated with function type 'long (long)'}} +}; + +X<int> f() { return 0; } + +struct XField { + X<float(int)> xf; // expected-note{{in instantiation of template class 'struct X<float (int)>' requested here}} +}; + +void test_subscript(X<double> *ptr1, X<int(int)> *ptr2, int i) { + (void)ptr1[i]; + (void)ptr2[i]; // expected-note{{in instantiation of template class 'struct X<int (int)>' requested here}} +} + +void test_arith(X<signed char> *ptr1, X<unsigned char> *ptr2, + X<char(char)> *ptr3, X<short(short)> *ptr4) { + (void)(ptr1 + 5); + // FIXME: if I drop the ')' after void, below, it still parses (!) + (void)(5 + ptr2); + (void)(ptr3 + 5); // expected-note{{in instantiation of template class 'struct X<char (char)>' requested here}} + (void)(5 + ptr4); // expected-note{{in instantiation of template class 'struct X<short (short)>' requested here}} +} + +void test_new() { + (void)new X<float>(0); + (void)new X<float(float)>; // expected-note{{in instantiation of template class 'struct X<float (float)>' requested here}} +} + +void test_memptr(X<long> *p1, long X<long>::*pm1, + X<long(long)> *p2, long (X<long(long)>::*pm2)(long)) { + (void)(p1->*pm1); + (void)(p2->*pm2); // expected-note{{in instantiation of template class 'struct X<long (long)>' requested here}} +} |