[cfe-commits] r81939 - in /cfe/trunk: lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp

Douglas Gregor dgregor at apple.com
Tue Sep 15 15:30:30 PDT 2009


Author: dgregor
Date: Tue Sep 15 17:30:29 2009
New Revision: 81939

URL: http://llvm.org/viewvc/llvm-project?rev=81939&view=rev
Log:
When implicitly declaring operators new, new[], delete, and delete[],
give them the appropriate exception specifications. This,
unfortunately, requires us to maintain and/or implicitly generate
handles to namespace "std" and the class "std::bad_alloc". However,
every other approach I've come up with was more hackish, and this
standard requirement itself is quite the hack.

Fixes PR4829.

Added:
    cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
    cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
Modified:
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Sep 15 17:30:29 2009
@@ -193,11 +193,11 @@
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
     ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
     CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
+    StdNamespace(0), StdBadAlloc(0),
     GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
     CompleteTranslationUnit(CompleteTranslationUnit),
     NumSFINAEErrors(0), CurrentInstantiationScope(0) {
 
-  StdNamespace = 0;
   TUScope = 0;
   if (getLangOptions().CPlusPlus)
     FieldCollector.reset(new CXXFieldCollector());

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Sep 15 17:30:29 2009
@@ -305,10 +305,13 @@
   /// For example, user-defined classes, built-in "id" type, etc.
   Scope *TUScope;
 
-  /// The C++ "std" namespace, where the standard library resides. Cached here
-  /// by GetStdNamespace
+  /// \brief The C++ "std" namespace, where the standard library resides.
   NamespaceDecl *StdNamespace;
 
+  /// \brief The C++ "std::bad_alloc" class, which is defined by the C++
+  /// standard library.
+  CXXRecordDecl *StdBadAlloc;
+  
   /// A flag to remember whether the implicit forms of operator new and delete
   /// have been declared.
   bool GlobalNewDeleteDeclared;
@@ -1337,8 +1340,6 @@
   void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
                                    ObjCMethodDecl *IntfMethod);
 
-  NamespaceDecl *GetStdNamespace();
-
   bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
                           ObjCInterfaceDecl *IDecl);
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Sep 15 17:30:29 2009
@@ -521,18 +521,6 @@
   return New;
 }
 
-/// GetStdNamespace - This method gets the C++ "std" namespace. This is where
-/// everything from the standard library is defined.
-NamespaceDecl *Sema::GetStdNamespace() {
-  if (!StdNamespace) {
-    IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std");
-    DeclContext *Global = Context.getTranslationUnitDecl();
-    Decl *Std = LookupQualifiedName(Global, StdIdent, LookupNamespaceName);
-    StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std);
-  }
-  return StdNamespace;
-}
-
 /// MergeTypeDefDecl - We just parsed a typedef 'New' which has the
 /// same name and scope as a previous declaration 'Old'.  Figure out
 /// how to resolve this situation, merging decls or emitting
@@ -3990,7 +3978,7 @@
   DeclContext *SearchDC = CurContext;
   DeclContext *DC = CurContext;
   NamedDecl *PrevDecl = 0;
-
+  bool isStdBadAlloc = false;
   bool Invalid = false;
 
   if (Name && SS.isNotEmpty()) {
@@ -4067,6 +4055,19 @@
     PrevDecl = 0;
   }
 
+  if (getLangOptions().CPlusPlus && Name && DC && StdNamespace &&
+      DC->Equals(StdNamespace) && Name->isStr("bad_alloc")) {
+    // This is a declaration of or a reference to "std::bad_alloc".
+    isStdBadAlloc = true;
+    
+    if (!PrevDecl && StdBadAlloc) {
+      // std::bad_alloc has been implicitly declared (but made invisible to
+      // name lookup). Fill in this implicit declaration as the previous 
+      // declaration, so that the declarations get chained appropriately.
+      PrevDecl = StdBadAlloc;
+    }
+  }
+      
   if (PrevDecl) {
     // Check whether the previous declaration is usable.
     (void)DiagnoseUseOfDecl(PrevDecl, NameLoc);
@@ -4253,11 +4254,14 @@
 
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
     // struct X { int A; } D;    D should chain to X.
-    if (getLangOptions().CPlusPlus)
+    if (getLangOptions().CPlusPlus) {
       // FIXME: Look for a way to use RecordDecl for simple structs.
       New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
                                   cast_or_null<CXXRecordDecl>(PrevDecl));
-    else
+      
+      if (isStdBadAlloc && (!StdBadAlloc || StdBadAlloc->isImplicit()))
+        StdBadAlloc = cast<CXXRecordDecl>(New);
+    } else
       New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
                                cast_or_null<RecordDecl>(PrevDecl));
   }

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Sep 15 17:30:29 2009
@@ -2374,6 +2374,21 @@
       Diag(PrevDecl->getLocation(), diag::note_previous_definition);
       Namespc->setInvalidDecl();
       // Continue on to push Namespc as current DeclContext and return it.
+    } else if (II->isStr("std") && 
+               CurContext->getLookupContext()->isTranslationUnit()) {
+      // This is the first "real" definition of the namespace "std", so update
+      // our cache of the "std" namespace to point at this definition.
+      if (StdNamespace) {
+        // We had already defined a dummy namespace "std". Link this new 
+        // namespace definition to the dummy namespace "std".
+        StdNamespace->setNextNamespace(Namespc);
+        StdNamespace->setLocation(IdentLoc);
+        Namespc->setOriginalNamespace(StdNamespace->getOriginalNamespace());
+      }
+      
+      // Make our StdNamespace cache point at the first real definition of the
+      // "std" namespace.
+      StdNamespace = Namespc;
     }
 
     PushOnScopeChains(Namespc, DeclRegionScope);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Sep 15 17:30:29 2009
@@ -61,8 +61,7 @@
 Action::OwningExprResult
 Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
                      bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
-  NamespaceDecl *StdNs = GetStdNamespace();
-  if (!StdNs)
+  if (!StdNamespace)
     return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
 
   if (isType)
@@ -70,7 +69,8 @@
     TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr();
 
   IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
-  Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName);
+  Decl *TypeInfoDecl = LookupQualifiedName(StdNamespace, TypeInfoII, 
+                                           LookupTagName);
   RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
   if (!TypeInfoRecordDecl)
     return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
@@ -661,12 +661,49 @@
 void Sema::DeclareGlobalNewDelete() {
   if (GlobalNewDeleteDeclared)
     return;
+  
+  // C++ [basic.std.dynamic]p2:
+  //   [...] The following allocation and deallocation functions (18.4) are 
+  //   implicitly declared in global scope in each translation unit of a 
+  //   program
+  //   
+  //     void* operator new(std::size_t) throw(std::bad_alloc);
+  //     void* operator new[](std::size_t) throw(std::bad_alloc); 
+  //     void  operator delete(void*) throw(); 
+  //     void  operator delete[](void*) throw();
+  //
+  //   These implicit declarations introduce only the function names operator 
+  //   new, operator new[], operator delete, operator delete[].
+  //
+  // Here, we need to refer to std::bad_alloc, so we will implicitly declare
+  // "std" or "bad_alloc" as necessary to form the exception specification.
+  // However, we do not make these implicit declarations visible to name
+  // lookup.
+  if (!StdNamespace) {
+    // The "std" namespace has not yet been defined, so build one implicitly.
+    StdNamespace = NamespaceDecl::Create(Context, 
+                                         Context.getTranslationUnitDecl(),
+                                         SourceLocation(),
+                                         &PP.getIdentifierTable().get("std"));
+    StdNamespace->setImplicit(true);
+  }
+  
+  if (!StdBadAlloc) {
+    // The "std::bad_alloc" class has not yet been declared, so build it
+    // implicitly.
+    StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class, 
+                                        StdNamespace, 
+                                        SourceLocation(), 
+                                      &PP.getIdentifierTable().get("bad_alloc"), 
+                                        SourceLocation(), 0);
+    StdBadAlloc->setImplicit(true);
+  }
+  
   GlobalNewDeleteDeclared = true;
 
   QualType VoidPtr = Context.getPointerType(Context.VoidTy);
   QualType SizeT = Context.getSizeType();
 
-  // FIXME: Exception specifications are not added.
   DeclareGlobalAllocationFunction(
       Context.DeclarationNames.getCXXOperatorName(OO_New),
       VoidPtr, SizeT);
@@ -700,7 +737,19 @@
     }
   }
 
-  QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
+  QualType BadAllocType;
+  bool HasBadAllocExceptionSpec 
+    = (Name.getCXXOverloadedOperator() == OO_New ||
+       Name.getCXXOverloadedOperator() == OO_Array_New);
+  if (HasBadAllocExceptionSpec) {
+    assert(StdBadAlloc && "Must have std::bad_alloc declared");
+    BadAllocType = Context.getTypeDeclType(StdBadAlloc);
+  }
+  
+  QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
+                                            true, false,
+                                            HasBadAllocExceptionSpec? 1 : 0,
+                                            &BadAllocType);
   FunctionDecl *Alloc =
     FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
                          FnType, /*DInfo=*/0, FunctionDecl::None, false, true);

Added: cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp?rev=81939&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp Tue Sep 15 17:30:29 2009
@@ -0,0 +1,7 @@
+// RUN: clang -fsyntax-only -verify %s
+
+int *use_new(int N) {
+  return new int [N];
+}
+
+int std = 17;

Added: cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp?rev=81939&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp Tue Sep 15 17:30:29 2009
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int *use_new(int N) {
+  if (N == 1)
+    return new int;
+  
+  return new int [N];
+}
+
+void use_delete(int* ip, int N) {
+  if (N == 1)
+    delete ip;
+  else
+    delete [] ip;
+}
+
+namespace std {
+  class bad_alloc { };
+  
+  typedef __SIZE_TYPE__ size_t;
+}
+
+void* operator new(std::size_t) throw(std::bad_alloc); 
+void* operator new[](std::size_t) throw(std::bad_alloc); 
+void operator delete(void*) throw(); 
+void operator delete[](void*) throw();





More information about the cfe-commits mailing list