[cfe-commits] r72580 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h lib/Parse/DeclSpec.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExpr.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaType.cpp test/SemaCXX/exception-spec.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Fri May 29 11:02:33 PDT 2009


Author: cornedbee
Date: Fri May 29 13:02:33 2009
New Revision: 72580

URL: http://llvm.org/viewvc/llvm-project?rev=72580&view=rev
Log:
Reject incomplete types in exception specs.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/DeclSpec.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.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=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri May 29 13:02:33 2009
@@ -272,6 +272,9 @@
 def err_distant_exception_spec : Error<
   "exception specifications are not allowed beyond a single level "
   "of indirection">;
+def err_incomplete_in_exception_spec : Error<
+  "%select{|pointer to |member pointer to |reference to }1incomplete type %0 "
+  "is not allowed in exception specification">;
 
 // C++ access checking
 def err_class_redeclared_with_different_access : Error<

Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Fri May 29 13:02:33 2009
@@ -518,7 +518,12 @@
       : Ident(ident), IdentLoc(iloc), Param(param), 
         DefaultArgTokens(DefArgTokens) {}
   };
-  
+
+  struct TypeAndRange {
+    ActionBase::TypeTy *Ty;
+    SourceRange Range;
+  };
+
   struct FunctionTypeInfo {
     /// hasPrototype - This is true if the function had at least one typed
     /// argument.  If the function is () or (a,b,c), then it has no prototype,
@@ -559,9 +564,10 @@
     /// there are no arguments specified.
     ParamInfo *ArgInfo;
 
-    /// Exceptions - This is a pointer to a new[]'d array of TypeTy pointers
-    /// that contains the types in the function's exception specification.
-    ActionBase::TypeTy **Exceptions;
+    /// Exceptions - This is a pointer to a new[]'d array of TypeAndRange
+    /// objects that contain the types in the function's exception
+    /// specification and their locations.
+    TypeAndRange *Exceptions;
 
     /// freeArgs - reset the argument list to having zero arguments.  This is
     /// used in various places for error recovery.
@@ -700,6 +706,7 @@
                                      unsigned TypeQuals, bool hasExceptionSpec,
                                      bool hasAnyExceptionSpec,
                                      ActionBase::TypeTy **Exceptions,
+                                     SourceRange *ExceptionRanges,
                                      unsigned NumExceptions, SourceLocation Loc,
                                      Declarator &TheDeclarator);
   

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri May 29 13:02:33 2009
@@ -772,7 +772,8 @@
   OwningExprResult ParseThrowExpression();
   // EndLoc is filled with the location of the last token of the specification.
   bool ParseExceptionSpecification(SourceLocation &EndLoc,
-                                   std::vector<TypeTy*> &Exceptions,
+                                   llvm::SmallVector<TypeTy*, 2> &Exceptions,
+                                   llvm::SmallVector<SourceRange, 2> &Ranges,
                                    bool &hasAnyExceptionSpec);
 
   //===--------------------------------------------------------------------===//
@@ -1057,7 +1058,7 @@
   TPResult TryParseFunctionDeclarator();
   TPResult TryParseBracketDeclarator();
 
-  TypeResult ParseTypeName();
+  TypeResult ParseTypeName(SourceRange *Range = 0);
   void ParseBlockId();
   // EndLoc, if non-NULL, is filled with the location of the last token of
   // the attribute list.

Modified: cfe/trunk/lib/Parse/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/DeclSpec.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Parse/DeclSpec.cpp Fri May 29 13:02:33 2009
@@ -35,6 +35,7 @@
                                              bool hasExceptionSpec,
                                              bool hasAnyExceptionSpec,
                                              ActionBase::TypeTy **Exceptions,
+                                             SourceRange *ExceptionRanges,
                                              unsigned NumExceptions,
                                              SourceLocation Loc,
                                              Declarator &TheDeclarator) {
@@ -72,9 +73,11 @@
   }
   // new[] an exception array if needed
   if (NumExceptions) {
-    I.Fun.Exceptions = new ActionBase::TypeTy*[NumExceptions];
-    memcpy(I.Fun.Exceptions, Exceptions,
-           sizeof(ActionBase::TypeTy*)*NumExceptions);
+    I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
+    for (unsigned i = 0; i != NumExceptions; ++i) {
+      I.Fun.Exceptions[i].Ty = Exceptions[i];
+      I.Fun.Exceptions[i].Range = ExceptionRanges[i];
+    }
   }
   return I;
 }

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri May 29 13:02:33 2009
@@ -27,15 +27,17 @@
 ///         specifier-qualifier-list abstract-declarator[opt]
 ///
 /// Called type-id in C++.
-Action::TypeResult Parser::ParseTypeName() {
+Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
   // Parse the common declaration-specifiers piece.
   DeclSpec DS;
   ParseSpecifierQualifierList(DS);
-  
+
   // Parse the abstract-declarator, if present.
   Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
   ParseDeclarator(DeclaratorInfo);
-  
+  if (Range)
+    *Range = DeclaratorInfo.getSourceRange();
+
   if (DeclaratorInfo.isInvalidType())
     return true;
 
@@ -2273,9 +2275,8 @@
     DeclSpec DS;
     bool hasExceptionSpec = false;
     bool hasAnyExceptionSpec = false;
-    // FIXME: Does an empty vector ever allocate? Exception specifications are
-    // extremely rare, so we want something like a SmallVector<TypeTy*, 0>. :-)
-    std::vector<TypeTy*> Exceptions;
+    llvm::SmallVector<TypeTy*, 2> Exceptions;
+    llvm::SmallVector<SourceRange, 2> ExceptionRanges;
     if (getLang().CPlusPlus) {
       ParseTypeQualifierListOpt(DS, false /*no attributes*/);
       if (!DS.getSourceRange().getEnd().isInvalid())
@@ -2284,7 +2285,10 @@
       // Parse exception-specification[opt].
       if (Tok.is(tok::kw_throw)) {
         hasExceptionSpec = true;
-        ParseExceptionSpecification(Loc, Exceptions, hasAnyExceptionSpec);
+        ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+                                    hasAnyExceptionSpec);
+        assert(Exceptions.size() == ExceptionRanges.size() &&
+               "Produced different number of exception types and ranges.");
       }
     }
 
@@ -2297,14 +2301,14 @@
                                                DS.getTypeQualifiers(),
                                                hasExceptionSpec,
                                                hasAnyExceptionSpec,
-                                               Exceptions.empty() ? 0 :
-                                                 &Exceptions[0],
+                                               Exceptions.data(),
+                                               ExceptionRanges.data(),
                                                Exceptions.size(),
                                                LParenLoc, D),
                   Loc);
     return;
-  } 
-  
+  }
+
   // Alternatively, this parameter list may be an identifier list form for a
   // K&R-style function:  void foo(a,b,c)
   if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
@@ -2445,9 +2449,8 @@
   DeclSpec DS;
   bool hasExceptionSpec = false;
   bool hasAnyExceptionSpec = false;
-  // FIXME: Does an empty vector ever allocate? Exception specifications are
-  // extremely rare, so we want something like a SmallVector<TypeTy*, 0>. :-)
-  std::vector<TypeTy*> Exceptions;
+  llvm::SmallVector<TypeTy*, 2> Exceptions;
+  llvm::SmallVector<SourceRange, 2> ExceptionRanges;
   if (getLang().CPlusPlus) {
     // Parse cv-qualifier-seq[opt].
     ParseTypeQualifierListOpt(DS, false /*no attributes*/);
@@ -2457,7 +2460,10 @@
     // Parse exception-specification[opt].
     if (Tok.is(tok::kw_throw)) {
       hasExceptionSpec = true;
-      ParseExceptionSpecification(Loc, Exceptions, hasAnyExceptionSpec);
+      ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+                                  hasAnyExceptionSpec);
+      assert(Exceptions.size() == ExceptionRanges.size() &&
+             "Produced different number of exception types and ranges.");
     }
   }
 
@@ -2468,8 +2474,8 @@
                                              DS.getTypeQualifiers(),
                                              hasExceptionSpec,
                                              hasAnyExceptionSpec,
-                                             Exceptions.empty() ? 0 :
-                                               &Exceptions[0],
+                                             Exceptions.data(),
+                                             ExceptionRanges.data(),
                                              Exceptions.size(), LParenLoc, D),
                 Loc);
 }
@@ -2545,7 +2551,7 @@
                                              SourceLocation(),
                                              &ParamInfo[0], ParamInfo.size(),
                                              /*TypeQuals*/0,
-                                             /*exception*/false, false, 0, 0,
+                                             /*exception*/false, false, 0, 0, 0,
                                              LParenLoc, D),
                 RLoc);
 }

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Fri May 29 13:02:33 2009
@@ -1191,7 +1191,10 @@
 ///         type-id-list ',' type-id
 ///
 bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
-                                         std::vector<TypeTy*> &Exceptions,
+                                         llvm::SmallVector<TypeTy*, 2>
+                                             &Exceptions,
+                                         llvm::SmallVector<SourceRange, 2>
+                                             &Ranges,
                                          bool &hasAnyExceptionSpec) {
   assert(Tok.is(tok::kw_throw) && "expected throw");
   
@@ -1214,10 +1217,13 @@
   }
 
   // Parse the sequence of type-ids.
+  SourceRange Range;
   while (Tok.isNot(tok::r_paren)) {
-    TypeResult Res(ParseTypeName());
-    if (!Res.isInvalid())
+    TypeResult Res(ParseTypeName(&Range));
+    if (!Res.isInvalid()) {
       Exceptions.push_back(Res.get());
+      Ranges.push_back(Range);
+    }
     if (Tok.is(tok::comma))
       ConsumeToken();
     else

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri May 29 13:02:33 2009
@@ -1481,7 +1481,7 @@
     ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, 
                                                        SourceLocation(),
                                                        0, 0, 0,
-                                                       false, false, 0, 0,
+                                                       false, false, 0, 0, 0,
                                                        CaretLoc, ParamInfo),
                           CaretLoc);
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri May 29 13:02:33 2009
@@ -349,6 +349,7 @@
   QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
                                 TagDecl **OwnedDecl = 0);
   DeclarationName GetNameForDeclarator(Declarator &D);
+  bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
   bool CheckDistantExceptionSpec(QualType T);
 
   QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri May 29 13:02:33 2009
@@ -3176,7 +3176,7 @@
   assert(!Error && "Error setting up implicit decl!");
   Declarator D(DS, Declarator::BlockContext);
   D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
-                                             0, 0, false, false, 0, 0, Loc, D),
+                                             0, 0, false, false, 0,0,0, Loc, D),
                 SourceLocation());
   D.SetIdentifier(&II, Loc);
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri May 29 13:02:33 2009
@@ -760,13 +760,17 @@
           // function takes no arguments.
           llvm::SmallVector<QualType, 4> Exceptions;
           Exceptions.reserve(FTI.NumExceptions);
-          for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei)
-            Exceptions.push_back(
-              QualType::getFromOpaquePtr(FTI.Exceptions[ei]));
+          for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+            QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+            // Check that the type is valid for an exception spec, and drop it
+            // if not.
+            if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+              Exceptions.push_back(ET);
+          }
           T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
                                       FTI.hasExceptionSpec,
                                       FTI.hasAnyExceptionSpec,
-                                      FTI.NumExceptions, Exceptions.data());
+                                      Exceptions.size(), Exceptions.data());
         } else if (FTI.isVariadic) {
           // We allow a zero-parameter variadic function in C if the
           // function is marked with the "overloadable"
@@ -843,14 +847,19 @@
 
         llvm::SmallVector<QualType, 4> Exceptions;
         Exceptions.reserve(FTI.NumExceptions);
-        for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei)
-          Exceptions.push_back(QualType::getFromOpaquePtr(FTI.Exceptions[ei]));
+        for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+          QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+          // Check that the type is valid for an exception spec, and drop it if
+          // not.
+          if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+            Exceptions.push_back(ET);
+        }
 
         T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(),
                                     FTI.isVariadic, FTI.TypeQuals,
                                     FTI.hasExceptionSpec,
                                     FTI.hasAnyExceptionSpec,
-                                    FTI.NumExceptions, Exceptions.data());
+                                    Exceptions.size(), Exceptions.data());
       }
       break;
     }
@@ -953,6 +962,43 @@
   return T;
 }
 
+/// CheckSpecifiedExceptionType - Check if the given type is valid in an
+/// exception specification. Incomplete types, or pointers to incomplete types
+/// other than void are not allowed.
+bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
+  // FIXME: This may not correctly work with the fix for core issue 437,
+  // where a class's own type is considered complete within its body.
+
+  // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+  //   an incomplete type.
+  if (T->isIncompleteType())
+    return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
+      << Range << T << /*direct*/0;
+
+  // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+  //   an incomplete type a pointer or reference to an incomplete type, other
+  //   than (cv) void*.
+  // The standard does not mention member pointers, but it has to mean them too.
+  int kind;
+  if (const PointerType* IT = T->getAsPointerType()) {
+    T = IT->getPointeeType();
+    kind = 1;
+  } else if (const MemberPointerType* IT = T->getAsMemberPointerType()) {
+    T = IT->getPointeeType();
+    kind = 2;
+  } else if (const ReferenceType* IT = T->getAsReferenceType()) {
+    T = IT->getPointeeType();
+    kind = 3;
+  } else
+    return false;
+
+  if (T->isIncompleteType() && !T->isVoidType())
+    return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
+      << Range << T << /*indirect*/kind;
+
+  return false;
+}
+
 /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
 /// to member to a function with an exception specification. This means that
 /// it is invalid to add another level of indirection.

Modified: cfe/trunk/test/SemaCXX/exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exception-spec.cpp?rev=72580&r1=72579&r2=72580&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/exception-spec.cpp Fri May 29 13:02:33 2009
@@ -23,3 +23,13 @@
 void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
 // Pointer to function returning pointer to pointer to function with spec
 void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
+
+struct Incomplete;
+
+// Exception spec must not have incomplete types, or pointers to them, except
+// void.
+void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
+void ic2() throw(Incomplete); // expected-error {{incomplete type 'struct Incomplete' is not allowed in exception specification}}
+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}}





More information about the cfe-commits mailing list