diff options
-rw-r--r-- | lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 59 | ||||
-rw-r--r-- | test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp | 7 | ||||
-rw-r--r-- | test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp | 25 |
7 files changed, 126 insertions, 25 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 5a31296781..3f734105d8 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -193,11 +193,11 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, 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()); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 84e73a6fec..ff99475212 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -305,10 +305,13 @@ public: /// 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 @@ public: void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod, ObjCMethodDecl *IntfMethod); - NamespaceDecl *GetStdNamespace(); - bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, ObjCInterfaceDecl *IDecl); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c7bd31160a..696c10a941 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -521,18 +521,6 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, 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 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; NamedDecl *PrevDecl = 0; - + bool isStdBadAlloc = false; bool Invalid = false; if (Name && SS.isNotEmpty()) { @@ -4067,6 +4055,19 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, 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 @@ CreateNewDecl: // 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)); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9e49778250..a971b8a281 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2374,6 +2374,21 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, 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); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0054af3493..503e318afa 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -61,8 +61,7 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, 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 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, 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 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, 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 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, } } - 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); diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp new file mode 100644 index 0000000000..b6b3e24bd8 --- /dev/null +++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp @@ -0,0 +1,7 @@ +// RUN: clang -fsyntax-only -verify %s + +int *use_new(int N) { + return new int [N]; +} + +int std = 17; diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp new file mode 100644 index 0000000000..f3499e4286 --- /dev/null +++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp @@ -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(); |