[cfe-commits] r74943 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaType.cpp test/SemaCXX/exception-spec.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Tue Jul 7 13:30:04 PDT 2009
Author: cornedbee
Date: Tue Jul 7 15:29:57 2009
New Revision: 74943
URL: http://llvm.org/viewvc/llvm-project?rev=74943&view=rev
Log:
Implement checking of exception spec compatibility for overriding virtual functions.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaCXX/exception-spec.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=74943&r1=74942&r2=74943&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jul 7 15:29:57 2009
@@ -289,6 +289,9 @@
"in exception specification">;
def err_mismatched_exception_spec : Error<
"exception specification in declaration does not match previous declaration">;
+def err_override_exception_spec : Error<
+ "exception specification of overriding function is more lax than "
+ "base version">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=74943&r1=74942&r2=74943&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jul 7 15:29:57 2009
@@ -398,6 +398,9 @@
bool CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
+ bool CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID,
+ const FunctionProtoType *Superset, SourceLocation SuperLoc,
+ const FunctionProtoType *Subset, SourceLocation SubLoc);
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
@@ -1981,11 +1984,15 @@
std::string getAmbiguousPathsDisplayString(BasePaths &Paths);
- /// CheckReturnTypeCovariance - Checks whether two types are covariant,
- /// according to C++ [class.virtual]p5.
- bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
+ /// CheckOverridingFunctionReturnType - Checks whether the return types are
+ /// covariant, according to C++ [class.virtual]p5.
+ bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
-
+
+ /// CheckOverridingFunctionExceptionSpec - Checks whether the exception
+ /// spec is a subset of base spec.
+ bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
//===--------------------------------------------------------------------===//
// C++ Access Control
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=74943&r1=74942&r2=74943&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jul 7 15:29:57 2009
@@ -2244,7 +2244,8 @@
for (BasePaths::decl_iterator I = Paths.found_decls_begin(),
E = Paths.found_decls_end(); I != E; ++I) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
- if (!CheckOverridingFunctionReturnType(NewMD, OldMD))
+ if (!CheckOverridingFunctionReturnType(NewMD, OldMD) &&
+ !CheckOverridingFunctionExceptionSpec(NewMD, OldMD))
NewMD->addOverriddenMethod(OldMD);
}
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=74943&r1=74942&r2=74943&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jul 7 15:29:57 2009
@@ -882,7 +882,7 @@
i != e; ++i) {
// Traverse the record, looking for methods.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
- // If the method is pre virtual, add it to the methods vector.
+ // If the method is pure virtual, add it to the methods vector.
if (MD->isPure()) {
Methods.push_back(MD);
continue;
@@ -3223,6 +3223,17 @@
return false;
}
+bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old)
+{
+ return CheckExceptionSpecSubset(diag::err_override_exception_spec,
+ diag::note_overridden_virtual_function,
+ Old->getType()->getAsFunctionProtoType(),
+ Old->getLocation(),
+ New->getType()->getAsFunctionProtoType(),
+ New->getLocation());
+}
+
/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
/// initializer for the declaration 'Dcl'.
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=74943&r1=74942&r2=74943&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jul 7 15:29:57 2009
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInherit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -1237,6 +1238,95 @@
return true;
}
+/// CheckExceptionSpecSubset - Check whether the second function type's
+/// exception specification is a subset (or equivalent) of the first function
+/// type. This is used by override and pointer assignment checks.
+bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID,
+ const FunctionProtoType *Superset, SourceLocation SuperLoc,
+ const FunctionProtoType *Subset, SourceLocation SubLoc)
+{
+ // FIXME: As usual, we could be more specific in our error messages, but
+ // that better waits until we've got types with source locations.
+
+ // If superset contains everything, we're done.
+ if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
+ return false;
+
+ // It does not. If the subset contains everything, we've failed.
+ if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
+ Diag(SubLoc, DiagID);
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+
+ // Neither contains everything. Do a proper comparison.
+ for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
+ SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
+ // Take one type from the subset.
+ QualType CanonicalSubT = Context.getCanonicalType(*SubI);
+ bool SubIsPointer = false;
+ if (const ReferenceType *RefTy = CanonicalSubT->getAsReferenceType())
+ CanonicalSubT = RefTy->getPointeeType();
+ if (const PointerType *PtrTy = CanonicalSubT->getAsPointerType()) {
+ CanonicalSubT = PtrTy->getPointeeType();
+ SubIsPointer = true;
+ }
+ bool SubIsClass = CanonicalSubT->isRecordType();
+ CanonicalSubT.setCVRQualifiers(0);
+
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
+
+ bool Contained = false;
+ // Make sure it's in the superset.
+ for (FunctionProtoType::exception_iterator SuperI =
+ Superset->exception_begin(), SuperE = Superset->exception_end();
+ SuperI != SuperE; ++SuperI) {
+ QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
+ // SubT must be SuperT or derived from it, or pointer or reference to
+ // such types.
+ if (const ReferenceType *RefTy = CanonicalSuperT->getAsReferenceType())
+ CanonicalSuperT = RefTy->getPointeeType();
+ if (SubIsPointer) {
+ if (const PointerType *PtrTy = CanonicalSuperT->getAsPointerType())
+ CanonicalSuperT = PtrTy->getPointeeType();
+ else {
+ continue;
+ }
+ }
+ CanonicalSuperT.setCVRQualifiers(0);
+ // If the types are the same, move on to the next type in the subset.
+ if (CanonicalSubT == CanonicalSuperT) {
+ Contained = true;
+ break;
+ }
+
+ // Otherwise we need to check the inheritance.
+ if (!SubIsClass || !CanonicalSuperT->isRecordType())
+ continue;
+
+ Paths.clear();
+ if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
+ continue;
+
+ if (Paths.isAmbiguous(CanonicalSuperT))
+ continue;
+
+ // FIXME: Check base access. Don't forget to enable path recording.
+
+ Contained = true;
+ break;
+ }
+ if (!Contained) {
+ Diag(SubLoc, DiagID);
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+ }
+ // We've run the gauntlet.
+ return false;
+}
+
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
/// declarator
QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
Modified: cfe/trunk/test/SemaCXX/exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exception-spec.cpp?rev=74943&r1=74942&r2=74943&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/exception-spec.cpp Tue Jul 7 15:29:57 2009
@@ -61,3 +61,54 @@
// Top-level const doesn't matter.
void r8() throw(int);
void r8() throw(const int);
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct Base
+{
+ virtual void f1() throw();
+ virtual void f2();
+ virtual void f3() throw(...);
+ virtual void f4() throw(int, float);
+
+ virtual void f5() throw(int, float);
+ virtual void f6() throw(A);
+ virtual void f7() throw(A, int, float);
+ virtual void f8();
+
+ virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
+ virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
+ virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
+ virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
+};
+struct Derived : Base
+{
+ virtual void f1() throw();
+ virtual void f2() throw(...);
+ virtual void f3();
+ virtual void f4() throw(float, int);
+
+ virtual void f5() throw(float);
+ virtual void f6() throw(B1);
+ virtual void f7() throw(B1, B2, int);
+ virtual void f8() throw(B2, B2, int, float, char, double, bool);
+
+ virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
+};
More information about the cfe-commits
mailing list