diff options
author | Anders Carlsson <andersca@mac.com> | 2009-09-13 21:33:06 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-09-13 21:33:06 +0000 |
commit | 2c59d3c19715cb318a0a5939c735b8345d14d281 (patch) | |
tree | 983a3c3341ce9db1748ceb7f291bf26189a408fa | |
parent | 8195bc932d27e21be46b9a1f8ce268ebd419246b (diff) |
Perform the C++ specific semantic checks of a function declaration after it's been merged with the previous declaration. This ensures that getPreviousDecl() will have the right value when ActOnConversionDeclarator is called.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81720 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 82 | ||||
-rw-r--r-- | test/SemaCXX/conversion-function.cpp | 11 |
2 files changed, 52 insertions, 41 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 002372aa90..c7bd31160a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2808,42 +2808,6 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, if (NewFD->isMain()) CheckMain(NewFD); - // Semantic checking for this function declaration (in isolation). - if (getLangOptions().CPlusPlus) { - // C++-specific checks. - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { - CheckConstructor(Constructor); - } else if (isa<CXXDestructorDecl>(NewFD)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); - QualType ClassType = Context.getTypeDeclType(Record); - if (!ClassType->isDependentType()) { - DeclarationName Name - = Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(ClassType)); - if (NewFD->getDeclName() != Name) { - Diag(NewFD->getLocation(), diag::err_destructor_name); - return NewFD->setInvalidDecl(); - } - } - Record->setUserDeclaredDestructor(true); - // C++ [class]p4: A POD-struct is an aggregate class that has [...] no - // user-defined destructor. - Record->setPOD(false); - - // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- - // declared destructor. - // FIXME: C++0x: don't do this for "= default" destructors - Record->setHasTrivialDestructor(false); - } else if (CXXConversionDecl *Conversion - = dyn_cast<CXXConversionDecl>(NewFD)) - ActOnConversionDeclarator(Conversion); - - // Extra checking for C++ overloaded operators (C++ [over.oper]). - if (NewFD->isOverloadedOperator() && - CheckOverloadedOperatorDeclaration(NewFD)) - return NewFD->setInvalidDecl(); - } - // Check for a previous declaration of this name. if (!PrevDecl && NewFD->isExternC()) { // Since we did not find anything by this name and we're declaring @@ -2911,11 +2875,47 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, } } - // In C++, check default arguments now that we have merged decls. Unless - // the lexical context is the class, because in this case this is done - // during delayed parsing anyway. - if (getLangOptions().CPlusPlus && !CurContext->isRecord()) - CheckCXXDefaultArguments(NewFD); + // Semantic checking for this function declaration (in isolation). + if (getLangOptions().CPlusPlus) { + // C++-specific checks. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { + CheckConstructor(Constructor); + } else if (isa<CXXDestructorDecl>(NewFD)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); + QualType ClassType = Context.getTypeDeclType(Record); + if (!ClassType->isDependentType()) { + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); + if (NewFD->getDeclName() != Name) { + Diag(NewFD->getLocation(), diag::err_destructor_name); + return NewFD->setInvalidDecl(); + } + } + Record->setUserDeclaredDestructor(true); + // C++ [class]p4: A POD-struct is an aggregate class that has [...] no + // user-defined destructor. + Record->setPOD(false); + + // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- + // declared destructor. + // FIXME: C++0x: don't do this for "= default" destructors + Record->setHasTrivialDestructor(false); + } else if (CXXConversionDecl *Conversion + = dyn_cast<CXXConversionDecl>(NewFD)) + ActOnConversionDeclarator(Conversion); + + // Extra checking for C++ overloaded operators (C++ [over.oper]). + if (NewFD->isOverloadedOperator() && + CheckOverloadedOperatorDeclaration(NewFD)) + return NewFD->setInvalidDecl(); + + // In C++, check default arguments now that we have merged decls. Unless + // the lexical context is the class, because in this case this is done + // during delayed parsing anyway. + if (!CurContext->isRecord()) + CheckCXXDefaultArguments(NewFD); + } } void Sema::CheckMain(FunctionDecl* FD) { diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp index 1ca1e689ea..cde2851bf3 100644 --- a/test/SemaCXX/conversion-function.cpp +++ b/test/SemaCXX/conversion-function.cpp @@ -64,3 +64,14 @@ struct Flip { operator Flop() const; }; Flop flop = Flip(); // expected-error {{cannot initialize 'flop' with an rvalue of type 'struct Flip'}} + +// This tests that we don't add the second conversion declaration to the list of user conversions +struct C { + operator const char *() const; +}; + +C::operator const char*() const { return 0; } + +void f(const C& c) { + const char* v = c; +} |