diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 103 | ||||
-rw-r--r-- | test/SemaCXX/nested-name-spec.cpp | 25 | ||||
-rw-r--r-- | test/SemaCXX/qualified-id-lookup.cpp | 1 |
4 files changed, 83 insertions, 48 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index f173c47229..91178d7b68 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -860,6 +860,8 @@ DIAG(err_expected_class_or_namespace, ERROR, "expected a class or namespace") DIAG(err_invalid_declarator_scope, ERROR, "definition or redeclaration of %0 not in a namespace enclosing %1") +DIAG(err_invalid_declarator_global_scope, ERROR, + "definition or redeclaration of %0 cannot name the global scope") DIAG(err_invalid_declarator_in_function, ERROR, "definition or redeclaration of %0 not allowed inside a function") DIAG(err_not_tag_in_scope, ERROR, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e31f376d86..22b8ef2b1f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1139,14 +1139,14 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) { return DeclarationName(); } -/// isNearlyMatchingMemberFunction - Determine whether the C++ member -/// functions Declaration and Definition are "nearly" matching. This -/// heuristic is used to improve diagnostics in the case where an -/// out-of-line member function definition doesn't match any -/// declaration within the class. -static bool isNearlyMatchingMemberFunction(ASTContext &Context, - FunctionDecl *Declaration, - FunctionDecl *Definition) { +/// isNearlyMatchingFunction - Determine whether the C++ functions +/// Declaration and Definition are "nearly" matching. This heuristic +/// is used to improve diagnostics in the case where an out-of-line +/// function definition doesn't match any declaration within +/// the class or namespace. +static bool isNearlyMatchingFunction(ASTContext &Context, + FunctionDecl *Declaration, + FunctionDecl *Definition) { if (Declaration->param_size() != Definition->param_size()) return false; for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) { @@ -1219,17 +1219,21 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl, // In this case, PrevDecl will point to the overload set // containing the two f's declared in X, but neither of them // matches. - if (!CurContext->Encloses(DC)) { + + // First check whether we named the global scope. + if (isa<TranslationUnitDecl>(DC)) { + Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope) + << Name << D.getCXXScopeSpec().getRange(); + } else if (!CurContext->Encloses(DC)) { // The qualifying scope doesn't enclose the original declaration. // Emit diagnostic based on current scope. SourceLocation L = D.getIdentifierLoc(); SourceRange R = D.getCXXScopeSpec().getRange(); - if (isa<FunctionDecl>(CurContext)) { + if (isa<FunctionDecl>(CurContext)) Diag(L, diag::err_invalid_declarator_in_function) << Name << R; - } else { + else Diag(L, diag::err_invalid_declarator_scope) - << Name << cast<NamedDecl>(DC)->getDeclName() << R; - } + << Name << cast<NamedDecl>(DC) << R; InvalidDecl = true; } } @@ -1628,10 +1632,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Merge the decl with the existing one if appropriate. Since C functions // are in a flat namespace, make sure we consider decls in outer scopes. + bool Redeclaration = false; if (PrevDecl && (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) { - bool Redeclaration = false; - // If C++, determine whether NewFD is an overload of PrevDecl or // a declaration that requires merging. If it's an overload, // there's no more work to do here; we'll just add the new @@ -1664,40 +1667,46 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } } + } - if (!Redeclaration && D.getCXXScopeSpec().isSet()) { - // The user tried to provide an out-of-line definition for a - // member function, but there was no such member function - // declared (C++ [class.mfct]p2). For example: - // - // class X { - // void f() const; - // }; - // - // void X::f() { } // ill-formed - // - // Complain about this problem, and attempt to suggest close - // matches (e.g., those that differ only in cv-qualifiers and - // whether the parameter types are references). - Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << cast<CXXRecordDecl>(DC)->getDeclName() - << D.getCXXScopeSpec().getRange(); - InvalidDecl = true; - - LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, - true); - assert(!Prev.isAmbiguous() && - "Cannot have an ambiguity in previous-declaration lookup"); - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); - Func != FuncEnd; ++Func) { - if (isa<CXXMethodDecl>(*Func) && - isNearlyMatchingMemberFunction(Context, cast<FunctionDecl>(*Func), - NewFD)) - Diag((*Func)->getLocation(), diag::note_member_def_close_match); - } - - PrevDecl = 0; + if (D.getCXXScopeSpec().isSet() && + (!PrevDecl || !Redeclaration)) { + // The user tried to provide an out-of-line definition for a + // function that is a member of a class or namespace, but there + // was no such member function declared (C++ [class.mfct]p2, + // C++ [namespace.memdef]p2). For example: + // + // class X { + // void f() const; + // }; + // + // void X::f() { } // ill-formed + // + // Complain about this problem, and attempt to suggest close + // matches (e.g., those that differ only in cv-qualifiers and + // whether the parameter types are references). + DeclarationName CtxName; + if (DC->isRecord()) + CtxName = cast<RecordDecl>(DC)->getDeclName(); + else if (DC->isNamespace()) + CtxName = cast<NamespaceDecl>(DC)->getDeclName(); + // FIXME: global scope + Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) + << CtxName << D.getCXXScopeSpec().getRange(); + InvalidDecl = true; + + LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, + true); + assert(!Prev.isAmbiguous() && + "Cannot have an ambiguity in previous-declaration lookup"); + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + if (isa<FunctionDecl>(*Func) && + isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD)) + Diag((*Func)->getLocation(), diag::note_member_def_close_match); } + + PrevDecl = 0; } // Handle attributes. We need to have merged decls when handling attributes diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index b48207345a..0c160075bf 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -123,3 +123,28 @@ Operators Operators::operator+(const Operators&) const { Operators::operator bool() { return true; } + +namespace A { + void g(int&); // expected-note{{member declaration nearly matches}} +} + +void A::f() {} // expected-error{{out-of-line definition does not match any declaration in 'A'}} + +void A::g(const int&) { } // expected-error{{out-of-line definition does not match any declaration in 'A'}} + +struct Struct { }; + +void Struct::f() { } // expected-error{{out-of-line definition does not match any declaration in 'Struct'}} + +void global_func(int); +void global_func2(int); + +namespace N { + void ::global_func(int) { } // expected-error{{definition or redeclaration of 'global_func' cannot name the global scope}} + + void f(); + // FIXME: if we move this to a separate definition of N, things break! +} +void ::global_func2(int) { } // expected-error{{definition or redeclaration of 'global_func2' cannot name the global scope}} + +void N::f() { } // okay diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp index e5721e00ee..2783710fcb 100644 --- a/test/SemaCXX/qualified-id-lookup.cpp +++ b/test/SemaCXX/qualified-id-lookup.cpp @@ -109,4 +109,3 @@ struct Undef { // expected-note{{definition of 'struct Undef' is not complete un int Undef::f() { return sizeof(Undef); } - |