]> granicus.if.org Git - clang/commitdiff
Catch function redeclarations with incompatible exception specifications.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sat, 4 Jul 2009 11:39:00 +0000 (11:39 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sat, 4 Jul 2009 11:39:00 +0000 (11:39 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74787 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaType.cpp
test/SemaCXX/exception-spec.cpp

index af8999e305ea68076cb31f061d5ddc08b82191c0..b1a73d05a45fc7449bff7b7f18d7108c7a4ab93b 100644 (file)
@@ -287,6 +287,8 @@ def err_distant_exception_spec : Error<
 def err_incomplete_in_exception_spec : Error<
   "%select{|pointer to |reference to }1incomplete type %0 is not allowed "
   "in exception specification">;
+def err_mismatched_exception_spec : Error<
+  "exception specification in declaration does not match previous declaration">;
 
 // C++ access checking
 def err_class_redeclared_with_different_access : Error<
index 72fb0a82a02da440c50d172681bc606feba0ec34..7af80c0261e4d9fce24aa1cafbc84de2701cfce0 100644 (file)
@@ -86,6 +86,7 @@ namespace clang {
   class ObjCMethodDecl;
   class ObjCPropertyDecl;
   class ObjCContainerDecl;
+  class FunctionProtoType;
   class BasePaths;
   struct MemberLookupCriteria;
   class CXXTemporary;
@@ -394,6 +395,9 @@ public:
   DeclarationName GetNameForDeclarator(Declarator &D);
   bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
   bool CheckDistantExceptionSpec(QualType T);
+  bool CheckEquivalentExceptionSpec(
+      const FunctionProtoType *Old, SourceLocation OldLoc,
+      const FunctionProtoType *New, SourceLocation NewLoc);
 
   QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
 
index d03576226204182f65d5e608c843d31da0dec2a3..75ceb1916555037b953cd66f7962e2c8a2ca6fd8 100644 (file)
@@ -258,6 +258,12 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
     }
   }
 
+  if (CheckEquivalentExceptionSpec(
+          Old->getType()->getAsFunctionProtoType(), Old->getLocation(),
+          New->getType()->getAsFunctionProtoType(), New->getLocation())) {
+    Invalid = true;
+  }
+
   return Invalid;
 }
 
index 7fa6d703c2af4c57ad8d2c6588cb1085387a48cc..3756df870c2c2b00b27e069bf6f895c4ec5104be 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/Parse/DeclSpec.h"
+#include "llvm/ADT/SmallPtrSet.h"
 using namespace clang;
 
 /// \brief Perform adjustment on the parameter type of a function.
@@ -1063,6 +1064,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
       break;
     }
     case DeclaratorChunk::MemberPointer:
+      // Verify that we're not building a pointer to pointer to function with
+      // exception specification.
+      if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
+        Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+        D.setInvalidType(true);
+        // Build the type anyway.
+      }
       // The scope spec must refer to a class, or be dependent.
       QualType ClsType;
       if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
@@ -1187,6 +1195,45 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
   return FnT->hasExceptionSpec();
 }
 
+/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
+/// exception specifications. Exception specifications are equivalent if
+/// they allow exactly the same set of exception types. It does not matter how
+/// that is achieved. See C++ [except.spec]p2.
+bool Sema::CheckEquivalentExceptionSpec(
+    const FunctionProtoType *Old, SourceLocation OldLoc,
+    const FunctionProtoType *New, SourceLocation NewLoc) {
+  bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
+  bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
+  if (OldAny && NewAny)
+    return false;
+  if (OldAny || NewAny) {
+    Diag(NewLoc, diag::err_mismatched_exception_spec);
+    Diag(OldLoc, diag::note_previous_declaration);
+    return true;
+  }
+
+  bool Success = true;
+  // Both have a definite exception spec. Collect the first set, then compare
+  // to the second.
+  llvm::SmallPtrSet<const Type*, 8> Types;
+  for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
+       E = Old->exception_end(); I != E; ++I)
+    Types.insert(Context.getCanonicalType(*I).getTypePtr());
+
+  for (FunctionProtoType::exception_iterator I = New->exception_begin(),
+       E = New->exception_end(); I != E && Success; ++I)
+    Success = Types.erase(Context.getCanonicalType(*I).getTypePtr());
+
+  Success = Success && Types.empty();
+
+  if (Success) {
+    return false;
+  }
+  Diag(NewLoc, diag::err_mismatched_exception_spec);
+  Diag(OldLoc, diag::note_previous_declaration);
+  return true;
+}
+
 /// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
 /// declarator
 QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
index ea02aac4915f1a06c3f79d185108843c68844798..5eba26e70c6f8b25766cbbce1119740743d6fa99 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify %s
+// RUN: clang-cc -fsyntax-only -verify -fms-extensions %s
 
 // Straight from the standard:
 // Plain function with spec
@@ -33,3 +33,31 @@ void ic2() throw(Incomplete); // expected-error {{incomplete type 'struct Incomp
 void ic3() throw(void*);
 void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'struct Incomplete' is not allowed in exception specification}}
 void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'struct Incomplete' is not allowed in exception specification}}
+
+// Redeclarations
+typedef int INT;
+void r1() throw(int);
+void r1() throw(int);
+
+void r2() throw(int);
+void r2() throw(INT);
+
+// throw-any spec and no spec at all are semantically equivalent
+void r3();
+void r3() throw(...);
+
+void r4() throw(int, float);
+void r4() throw(float, int);
+
+void r5() throw(int); // expected-note {{previous declaration}}
+void r5(); // expected-error {{exception specification in declaration does not match}}
+
+void r6() throw(...); // expected-note {{previous declaration}}
+void r6() throw(int); // expected-error {{exception specification in declaration does not match}}
+
+void r7() throw(int); // expected-note {{previous declaration}}
+void r7() throw(float); // expected-error {{exception specification in declaration does not match}}
+
+// Top-level const doesn't matter.
+void r8() throw(int);
+void r8() throw(const int);