diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 3b450f5d0790..005aab3fa6a1 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -44,7 +44,7 @@ namespace clang { DIAG_START_PARSE = DIAG_START_LEX + 300, DIAG_START_AST = DIAG_START_PARSE + 300, DIAG_START_SEMA = DIAG_START_AST + 100, - DIAG_START_ANALYSIS = DIAG_START_SEMA + 1000, + DIAG_START_ANALYSIS = DIAG_START_SEMA + 1100, DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 }; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index bf2acfc06b9b..d92bb9cdc9b3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1746,7 +1746,9 @@ def err_not_tag_in_scope : Error< def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; - +def err_incomplete_object_call : Error< + "incomplete type in call to object of type %0">; + def warn_condition_is_assignment : Warning<"using the result of an " "assignment as a condition without parentheses">, InGroup; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5b40aacc29c5..5c3e131eb4f3 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5086,6 +5086,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, AddMethodCandidate(cast(*Oper), Object, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); + if (RequireCompleteType(LParenLoc, Object->getType(), + PartialDiagnostic(diag::err_incomplete_object_call) + << Object->getSourceRange())) + return true; + // C++ [over.call.object]p2: // In addition, for each conversion function declared in T of the // form @@ -5103,33 +5108,30 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. + // FIXME: Look in base classes for more conversion operators! + OverloadedFunctionDecl *Conversions + = cast(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) { - // FIXME: Look in base classes for more conversion operators! - OverloadedFunctionDecl *Conversions - = cast(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - CXXConversionDecl *Conv; - FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); + // Skip over templated conversion functions; they aren't + // surrogates. + if (ConvTemplate) + continue; - // Skip over templated conversion functions; they aren't - // surrogates. - if (ConvTemplate) - continue; + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs()) + ConvType = ConvPtrType->getPointeeType(); - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAs()) - ConvType = ConvPtrType->getPointeeType(); - - if (const FunctionProtoType *Proto = ConvType->getAs()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); - } + if (const FunctionProtoType *Proto = ConvType->getAs()) + AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); } // Perform overload resolution. diff --git a/clang/test/SemaCXX/incomplete-call.cpp b/clang/test/SemaCXX/incomplete-call.cpp index 08bfdefd6247..3ce898a76f2c 100644 --- a/clang/test/SemaCXX/incomplete-call.cpp +++ b/clang/test/SemaCXX/incomplete-call.cpp @@ -40,3 +40,10 @@ void g() { (b.*mfp)(); // expected-error {{calling function with incomplete return type 'struct A'}} } + + +struct C; // expected-note{{forward declaration}} + +void test_incomplete_object_call(C& c) { + c(); // expected-error{{incomplete type in call to object of type}} +}