diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Decl.cpp | 9 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 46 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 82 |
5 files changed, 139 insertions, 7 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 49b9c6fc8b..e77661a9fb 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1039,6 +1039,15 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { return OO_None; } +/// getLiteralIdentifier - The literal suffix identifier this function +/// represents, if any. +const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { + if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName) + return getDeclName().getCXXLiteralIdentifier(); + else + return 0; +} + FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) return cast<FunctionDecl>(Info->getInstantiatedFrom()); diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 1fa2010786..ff810735bc 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -56,9 +56,14 @@ public: /// This identifier is stored here rather than directly in DeclarationName so as /// to allow Objective-C selectors, which are about a million times more common, /// to consume minimal memory. -class CXXLiteralOperatorIdName : public DeclarationNameExtra { +class CXXLiteralOperatorIdName + : public DeclarationNameExtra, public llvm::FoldingSetNode { public: IdentifierInfo *ID; + + void Profile(llvm::FoldingSetNodeID &FSID) { + FSID.AddPointer(ID); + } }; bool operator<(DeclarationName LHS, DeclarationName RHS) { @@ -358,6 +363,7 @@ void DeclarationName::dump() const { DeclarationNameTable::DeclarationNameTable() { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; + CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>; // Initialize the overloaded operator names. CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; @@ -369,16 +375,30 @@ DeclarationNameTable::DeclarationNameTable() { } DeclarationNameTable::~DeclarationNameTable() { - llvm::FoldingSet<CXXSpecialName> *set = + llvm::FoldingSet<CXXSpecialName> *SpecialNames = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); - llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end(); + llvm::FoldingSetIterator<CXXSpecialName> + SI = SpecialNames->begin(), SE = SpecialNames->end(); + + while (SI != SE) { + CXXSpecialName *n = &*SI++; + delete n; + } + - while (I != E) { - CXXSpecialName *n = &*I++; + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); + llvm::FoldingSetIterator<CXXLiteralOperatorIdName> + LI = LiteralNames->begin(), LE = LiteralNames->end(); + + while (LI != LE) { + CXXLiteralOperatorIdName *n = &*LI++; delete n; } - delete set; + delete SpecialNames; + delete LiteralNames; delete [] CXXOperatorNames; } @@ -433,9 +453,23 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { DeclarationName DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); + + llvm::FoldingSetNodeID ID; + ID.AddPointer(II); + + void *InsertPos = 0; + if (CXXLiteralOperatorIdName *Name = + LiteralNames->FindNodeOrInsertPos(ID, InsertPos)) + return DeclarationName (Name); + CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName; LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator; LiteralName->ID = II; + + LiteralNames->InsertNode(LiteralName, InsertPos); return DeclarationName(LiteralName); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 38657638b7..956776cf29 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2360,6 +2360,8 @@ public: bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); + //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 59cb447ecd..e53f141c96 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3487,7 +3487,12 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) return NewFD->setInvalidDecl(); - + + // Extra checking for C++0x literal operators (C++0x [over.literal]). + if (NewFD->getLiteralIdentifier() && + CheckLiteralOperatorDeclaration(NewFD)) + return NewFD->setInvalidDecl(); + // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done // during delayed parsing anyway. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ffd10c89f0..e10398af85 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5006,6 +5006,88 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { return false; } +/// CheckLiteralOperatorDeclaration - Check whether the declaration +/// of this literal operator function is well-formed. If so, returns +/// false; otherwise, emits appropriate diagnostics and returns true. +bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { + DeclContext *DC = FnDecl->getDeclContext(); + Decl::Kind Kind = DC->getDeclKind(); + if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace && + Kind != Decl::LinkageSpec) { + Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace) + << FnDecl->getDeclName(); + return true; + } + + bool Valid = false; + + // FIXME: Check for the one valid template signature + // template <char...> type operator "" name(); + + if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + // Check the first parameter + QualType T = (*Param)->getType(); + + // unsigned long long int and long double are allowed, but only + // alone. + // We also allow any character type; their omission seems to be a bug + // in n3000 + if (Context.hasSameType(T, Context.UnsignedLongLongTy) || + Context.hasSameType(T, Context.LongDoubleTy) || + Context.hasSameType(T, Context.CharTy) || + Context.hasSameType(T, Context.WCharTy) || + Context.hasSameType(T, Context.Char16Ty) || + Context.hasSameType(T, Context.Char32Ty)) { + if (++Param == FnDecl->param_end()) + Valid = true; + goto FinishedParams; + } + + // Otherwise it must be a pointer to const; let's strip those. + const PointerType *PT = T->getAs<PointerType>(); + if (!PT) + goto FinishedParams; + T = PT->getPointeeType(); + if (!T.isConstQualified()) + goto FinishedParams; + T = T.getUnqualifiedType(); + + // Move on to the second parameter; + ++Param; + + // If there is no second parameter, the first must be a const char * + if (Param == FnDecl->param_end()) { + if (Context.hasSameType(T, Context.CharTy)) + Valid = true; + goto FinishedParams; + } + + // const char *, const wchar_t*, const char16_t*, and const char32_t* + // are allowed as the first parameter to a two-parameter function + if (!(Context.hasSameType(T, Context.CharTy) || + Context.hasSameType(T, Context.WCharTy) || + Context.hasSameType(T, Context.Char16Ty) || + Context.hasSameType(T, Context.Char32Ty))) + goto FinishedParams; + + // The second and final parameter must be an std::size_t + T = (*Param)->getType().getUnqualifiedType(); + if (Context.hasSameType(T, Context.getSizeType()) && + ++Param == FnDecl->param_end()) + Valid = true; + } + + // FIXME: This diagnostic is absolutely terrible. +FinishedParams: + if (!Valid) { + Diag(FnDecl->getLocation(), diag::err_literal_operator_params) + << FnDecl->getDeclName(); + return true; + } + + return false; +} + /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ /// linkage specification, including the language and (if present) /// the '{'. ExternLoc is the location of the 'extern', LangLoc is |