[cfe-commits] r93315 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclarationName.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Decl.cpp lib/AST/DeclarationName.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/Parser/cxx0x-literal-operators.cpp test/SemaCXX/literal-operators.cpp

Sean Hunt rideau3 at gmail.com
Wed Jan 13 01:01:03 PST 2010


Author: coppro
Date: Wed Jan 13 03:01:02 2010
New Revision: 93315

URL: http://llvm.org/viewvc/llvm-project?rev=93315&view=rev
Log:
Implement semantic checking for C++ literal operators.
This now rejects literal operators that don't meet the requirements.
Templates are not yet checked for.

Added:
    cfe/trunk/test/SemaCXX/literal-operators.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclarationName.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclarationName.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/Parser/cxx0x-literal-operators.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=93315&r1=93314&r2=93315&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Jan 13 03:01:02 2010
@@ -1184,6 +1184,8 @@
 
   OverloadedOperatorKind getOverloadedOperator() const;
 
+  const IdentifierInfo *getLiteralIdentifier() const;
+
   /// \brief If this function is an instantiation of a member function
   /// of a class template specialization, retrieves the function from
   /// which it was instantiated.

Modified: cfe/trunk/include/clang/AST/DeclarationName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=93315&r1=93314&r2=93315&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclarationName.h (original)
+++ cfe/trunk/include/clang/AST/DeclarationName.h Wed Jan 13 03:01:02 2010
@@ -309,6 +309,7 @@
 class DeclarationNameTable {
   void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
   CXXOperatorIdName *CXXOperatorNames; // Operator names
+  void *CXXLiteralOperatorNames; // Actually a FoldingSet<...> *
 
   DeclarationNameTable(const DeclarationNameTable&);            // NONCOPYABLE
   DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=93315&r1=93314&r2=93315&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jan 13 03:01:02 2010
@@ -2341,6 +2341,13 @@
 def err_operator_delete_param_type : Error<
   "%0 takes type %1 as first parameter">;
 
+// C++ literal operators
+def err_literal_operator_outside_namespace : Error<
+  "literal operator %0 must be in a namespace or global scope">;
+// FIXME: This diagnostic sucks
+def err_literal_operator_params : Error<
+  "parameter declaration for literal operator %0 is not valid">;
+
 // C++ conversion functions
 def err_conv_function_not_member : Error<
   "conversion function must be a non-static member function">;

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=93315&r1=93314&r2=93315&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Jan 13 03:01:02 2010
@@ -1039,6 +1039,15 @@
     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());

Modified: cfe/trunk/lib/AST/DeclarationName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclarationName.cpp?rev=93315&r1=93314&r2=93315&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclarationName.cpp (original)
+++ cfe/trunk/lib/AST/DeclarationName.cpp Wed Jan 13 03:01:02 2010
@@ -56,9 +56,14 @@
 /// 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 @@
 
 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() {
-  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;
+  }
+
+
+  llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
+    = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
+                                                      (CXXLiteralOperatorNames);
+  llvm::FoldingSetIterator<CXXLiteralOperatorIdName>
+                           LI = LiteralNames->begin(), LE = LiteralNames->end();
 
-  while (I != E) {
-    CXXSpecialName *n = &*I++;
+  while (LI != LE) {
+    CXXLiteralOperatorIdName *n = &*LI++;
     delete n;
   }
 
-  delete set;
+  delete SpecialNames;
+  delete LiteralNames;
   delete [] CXXOperatorNames;
 }
 
@@ -433,9 +453,23 @@
 
 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);
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jan 13 03:01:02 2010
@@ -2360,6 +2360,8 @@
 
   bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl);
 
+  bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl);
+
   //===--------------------------------------------------------------------===//
   // C++ Templates [C++ 14]
   //

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 13 03:01:02 2010
@@ -3487,7 +3487,12 @@
     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.

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jan 13 03:01:02 2010
@@ -5006,6 +5006,88 @@
   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

Modified: cfe/trunk/test/Parser/cxx0x-literal-operators.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-literal-operators.cpp?rev=93315&r1=93314&r2=93315&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx0x-literal-operators.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-literal-operators.cpp Wed Jan 13 03:01:02 2010
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
 
-void operator "" (); // expected-error {{expected identifier}}
-void operator "k" foo(); // expected-error {{string literal after 'operator' must be '""'}}
-void operator "" tester (int);
+void operator "" (const char *); // expected-error {{expected identifier}}
+void operator "k" foo(const char *); // expected-error {{string literal after 'operator' must be '""'}}
+void operator "" tester (const char *);

Added: cfe/trunk/test/SemaCXX/literal-operators.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/literal-operators.cpp?rev=93315&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/literal-operators.cpp (added)
+++ cfe/trunk/test/SemaCXX/literal-operators.cpp Wed Jan 13 03:01:02 2010
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+#include <stddef.h>
+
+struct tag {
+  void operator "" tag_bad (const char *); // expected-error {{literal operator 'operator "" tag_bad' must be in a namespace or global scope}}
+  friend void operator "" tag_good (const char *);
+};
+
+namespace ns { void operator "" ns_good (const char *); }
+
+// Check extern "C++" declarations
+extern "C++" void operator "" extern_good (const char *);
+extern "C++" { void operator "" extern_good (const char *); }
+
+void fn () { void operator "" fn_bad (const char *); } // expected-error {{literal operator 'operator "" fn_bad' must be in a namespace or global scope}}
+
+// One-param declarations (const char * was already checked)
+void operator "" good (char);
+void operator "" good (wchar_t);
+void operator "" good (char16_t);
+void operator "" good (char32_t);
+void operator "" good (unsigned long long);
+void operator "" good (long double);
+
+// Two-param declarations
+void operator "" good (const char *, size_t);
+void operator "" good (const wchar_t *, size_t);
+void operator "" good (const char16_t *, size_t);
+void operator "" good (const char32_t *, size_t);
+
+// Check typedef and array equivalences
+void operator "" good (const char[]);
+typedef const char c;
+void operator "" good (c*);
+
+// Check extra cv-qualifiers
+void operator "" cv_good (volatile const char *, const size_t);
+
+// Template delcaration (not implemented yet)
+// template <char...> void operator "" good ();
+
+// FIXME: Test some invalid decls that might crop up.





More information about the cfe-commits mailing list