r288220 - [c++1z] Improve support for -fno-exceptions: we can't just ignore exception

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 29 16:13:55 PST 2016


Author: rsmith
Date: Tue Nov 29 18:13:55 2016
New Revision: 288220

URL: http://llvm.org/viewvc/llvm-project?rev=288220&view=rev
Log:
[c++1z] Improve support for -fno-exceptions: we can't just ignore exception
specifications in this mode in C++17, since they're part of the function type,
so check and diagnose them like we would if exceptions were enabled.

Better ideas welcome.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp
    cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=288220&r1=288219&r2=288220&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Nov 29 18:13:55 2016
@@ -1306,6 +1306,8 @@ def err_mismatched_exception_spec : Erro
   "exception specification in declaration does not match previous declaration">;
 def ext_mismatched_exception_spec : ExtWarn<err_mismatched_exception_spec.Text>,
   InGroup<MicrosoftExceptionSpec>;
+def warn_mismatched_exception_spec_no_exceptions : ExtWarn<err_mismatched_exception_spec.Text>,
+  InGroup<DiagGroup<"exception-spec-no-exceptions">>;
 def err_override_exception_spec : Error<
   "exception specification of overriding function is more lax than "
   "base version">;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=288220&r1=288219&r2=288220&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Nov 29 18:13:55 2016
@@ -1330,11 +1330,7 @@ public:
   bool CheckEquivalentExceptionSpec(
       const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
       const FunctionProtoType *Old, SourceLocation OldLoc,
-      const FunctionProtoType *New, SourceLocation NewLoc,
-      bool *MissingExceptionSpecification = nullptr,
-      bool *MissingEmptyExceptionSpecification = nullptr,
-      bool AllowNoexceptAllMatchWithNoSpec = false,
-      bool IsOperatorNew = false);
+      const FunctionProtoType *New, SourceLocation NewLoc);
   bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
                                 const PartialDiagnostic &NestedDiagID,
                                 const PartialDiagnostic &NoteID,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=288220&r1=288219&r2=288220&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Nov 29 18:13:55 2016
@@ -2949,15 +2949,6 @@ bool Sema::MergeFunctionDecl(FunctionDec
     // but do not necessarily update the type of New.
     if (CheckEquivalentExceptionSpec(Old, New))
       return true;
-    // If exceptions are disabled, we might not have resolved the exception spec
-    // of one or both declarations. Do so now in C++1z, so that we can properly
-    // compare the types.
-    if (getLangOpts().CPlusPlus1z) {
-      for (QualType T : {Old->getType(), New->getType()})
-        if (auto *FPT = T->getAs<FunctionProtoType>())
-          if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
-            ResolveExceptionSpec(New->getLocation(), FPT);
-    }
     OldQType = Context.getCanonicalType(Old->getType());
     NewQType = Context.getCanonicalType(New->getType());
 

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=288220&r1=288219&r2=288220&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Nov 29 18:13:55 2016
@@ -207,6 +207,14 @@ Sema::UpdateExceptionSpec(FunctionDecl *
     Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
 }
 
+static bool CheckEquivalentExceptionSpecImpl(
+    Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
+    const FunctionProtoType *Old, SourceLocation OldLoc,
+    const FunctionProtoType *New, SourceLocation NewLoc,
+    bool *MissingExceptionSpecification = nullptr,
+    bool *MissingEmptyExceptionSpecification = nullptr,
+    bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false);
+
 /// Determine whether a function has an implicitly-generated exception
 /// specification.
 static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
@@ -229,6 +237,12 @@ static bool hasImplicitExceptionSpec(Fun
 }
 
 bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+  // Just completely ignore this under -fno-exceptions prior to C++1z.
+  // In C++1z onwards, the exception specification is part of the type and
+  // we will diagnose mismatches anyway, so it's better to check for them here.
+  if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus1z)
+    return false;
+
   OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
   bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
   bool MissingExceptionSpecification = false;
@@ -243,8 +257,8 @@ bool Sema::CheckEquivalentExceptionSpec(
 
   // Check the types as written: they must match before any exception
   // specification adjustment is applied.
-  if (!CheckEquivalentExceptionSpec(
-        PDiag(DiagID), PDiag(diag::note_previous_declaration),
+  if (!CheckEquivalentExceptionSpecImpl(
+        *this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
         Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
         New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
         &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
@@ -395,11 +409,15 @@ bool Sema::CheckEquivalentExceptionSpec(
 bool Sema::CheckEquivalentExceptionSpec(
     const FunctionProtoType *Old, SourceLocation OldLoc,
     const FunctionProtoType *New, SourceLocation NewLoc) {
+  if (!getLangOpts().CXXExceptions)
+    return false;
+
   unsigned DiagID = diag::err_mismatched_exception_spec;
   if (getLangOpts().MicrosoftExt)
     DiagID = diag::ext_mismatched_exception_spec;
-  bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID),
-      PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc);
+  bool Result = CheckEquivalentExceptionSpecImpl(
+      *this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
+      Old, OldLoc, New, NewLoc);
 
   // In Microsoft mode, mismatching exception specifications just cause a warning.
   if (getLangOpts().MicrosoftExt)
@@ -413,30 +431,23 @@ bool Sema::CheckEquivalentExceptionSpec(
 /// \return \c false if the exception specifications match, \c true if there is
 /// a problem. If \c true is returned, either a diagnostic has already been
 /// produced or \c *MissingExceptionSpecification is set to \c true.
-bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
-                                        const PartialDiagnostic &NoteID,
-                                        const FunctionProtoType *Old,
-                                        SourceLocation OldLoc,
-                                        const FunctionProtoType *New,
-                                        SourceLocation NewLoc,
-                                        bool *MissingExceptionSpecification,
-                                        bool*MissingEmptyExceptionSpecification,
-                                        bool AllowNoexceptAllMatchWithNoSpec,
-                                        bool IsOperatorNew) {
-  // Just completely ignore this under -fno-exceptions.
-  if (!getLangOpts().CXXExceptions)
-    return false;
-
+static bool CheckEquivalentExceptionSpecImpl(
+    Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
+    const FunctionProtoType *Old, SourceLocation OldLoc,
+    const FunctionProtoType *New, SourceLocation NewLoc,
+    bool *MissingExceptionSpecification,
+    bool *MissingEmptyExceptionSpecification,
+    bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) {
   if (MissingExceptionSpecification)
     *MissingExceptionSpecification = false;
 
   if (MissingEmptyExceptionSpecification)
     *MissingEmptyExceptionSpecification = false;
 
-  Old = ResolveExceptionSpec(NewLoc, Old);
+  Old = S.ResolveExceptionSpec(NewLoc, Old);
   if (!Old)
     return false;
-  New = ResolveExceptionSpec(NewLoc, New);
+  New = S.ResolveExceptionSpec(NewLoc, New);
   if (!New)
     return false;
 
@@ -470,8 +481,8 @@ bool Sema::CheckEquivalentExceptionSpec(
   if (OldEST == EST_None && NewEST == EST_None)
     return false;
 
-  FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context);
-  FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context);
+  FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(S.Context);
+  FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(S.Context);
   if (OldNR == FunctionProtoType::NR_BadNoexcept ||
       NewNR == FunctionProtoType::NR_BadNoexcept)
     return false;
@@ -486,9 +497,9 @@ bool Sema::CheckEquivalentExceptionSpec(
   if (OldNR != NewNR &&
       OldNR != FunctionProtoType::NR_NoNoexcept &&
       NewNR != FunctionProtoType::NR_NoNoexcept) {
-    Diag(NewLoc, DiagID);
+    S.Diag(NewLoc, DiagID);
     if (NoteID.getDiagID() != 0 && OldLoc.isValid())
-      Diag(OldLoc, NoteID);
+      S.Diag(OldLoc, NoteID);
     return true;
   }
 
@@ -526,7 +537,7 @@ bool Sema::CheckEquivalentExceptionSpec(
   // As a special compatibility feature, under C++0x we accept no spec and
   // throw(std::bad_alloc) as equivalent for operator new and operator new[].
   // This is because the implicit declaration changed, but old code would break.
-  if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
+  if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) {
     const FunctionProtoType *WithExceptions = nullptr;
     if (OldEST == EST_None && NewEST == EST_Dynamic)
       WithExceptions = New;
@@ -567,9 +578,9 @@ bool Sema::CheckEquivalentExceptionSpec(
       return true;
     }
 
-    Diag(NewLoc, DiagID);
+    S.Diag(NewLoc, DiagID);
     if (NoteID.getDiagID() != 0 && OldLoc.isValid())
-      Diag(OldLoc, NoteID);
+      S.Diag(OldLoc, NoteID);
     return true;
   }
 
@@ -581,11 +592,11 @@ bool Sema::CheckEquivalentExceptionSpec(
   // to the second.
   llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
   for (const auto &I : Old->exceptions())
-    OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType());
+    OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType());
 
   for (const auto &I : New->exceptions()) {
-    CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType();
-    if(OldTypes.count(TypePtr))
+    CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType();
+    if (OldTypes.count(TypePtr))
       NewTypes.insert(TypePtr);
     else
       Success = false;
@@ -596,12 +607,24 @@ bool Sema::CheckEquivalentExceptionSpec(
   if (Success) {
     return false;
   }
-  Diag(NewLoc, DiagID);
+  S.Diag(NewLoc, DiagID);
   if (NoteID.getDiagID() != 0 && OldLoc.isValid())
-    Diag(OldLoc, NoteID);
+    S.Diag(OldLoc, NoteID);
   return true;
 }
 
+bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
+                                        const PartialDiagnostic &NoteID,
+                                        const FunctionProtoType *Old,
+                                        SourceLocation OldLoc,
+                                        const FunctionProtoType *New,
+                                        SourceLocation NewLoc) {
+  if (!getLangOpts().CXXExceptions)
+    return false;
+  return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc,
+                                          New, NewLoc);
+}
+
 /// 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.

Modified: cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp?rev=288220&r1=288219&r2=288220&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp Tue Nov 29 18:13:55 2016
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
+// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify -std=c++1z %s
 // expected-no-diagnostics
 #include <malloc.h>
 

Modified: cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp?rev=288220&r1=288219&r2=288220&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp Tue Nov 29 18:13:55 2016
@@ -10,10 +10,9 @@ template<typename T> void redecl1() noex
 template<bool A, bool B> void redecl2() noexcept(A); // expected-note {{previous}}
 template<bool A, bool B> void redecl2() noexcept(B); // expected-error {{conflicting types}}
 
-// These have the same canonical type.
-// FIXME: It's not clear whether this is supposed to be valid.
-template<typename A, typename B> void redecl3() throw(A);
-template<typename A, typename B> void redecl3() throw(B);
+// These have the same canonical type, but are still different.
+template<typename A, typename B> void redecl3() throw(A); // expected-note {{previous}}
+template<typename A, typename B> void redecl3() throw(B); // expected-error {{does not match previous}}
 
 typedef int I;
 template<bool B> void redecl4(I) noexcept(B);




More information about the cfe-commits mailing list