]> granicus.if.org Git - clang/commitdiff
Audit and finish the implementation of C++0x nullptr, fixing two
authorDouglas Gregor <dgregor@apple.com>
Sat, 21 May 2011 23:15:46 +0000 (23:15 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 21 May 2011 23:15:46 +0000 (23:15 +0000)
minor issues along the way:
  - Non-type template parameters of type 'std::nullptr_t' were not
  permitted.
  - We didn't properly introduce built-in operators for nullptr ==,
  !=, <, <=, >=, or > as candidate functions .

To my knowledge, there's only one (minor but annoying) part of nullptr
that hasn't been implemented: catching a thrown 'nullptr' as a pointer
or pointer-to-member, per C++0x [except.handle]p4.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131813 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LanguageExtensions.html
lib/Lex/PPMacroExpansion.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
test/Lexer/has_feature_cxx0x.cpp
test/SemaCXX/nullptr.cpp

index 066677c3d7df430180e04a10627b465130acb694..bc8ecb1bc937fef24ee9c44ece71fe481628b23e 100644 (file)
@@ -449,8 +449,7 @@ is enabled. clang does not currently implement this feature.</p>
 
 <p>Use <tt>__has_feature(cxx_nullptr)</tt> or
 <tt>__has_extension(cxx_nullptr)</tt> to determine if support for
-<tt>nullptr</tt> is enabled. clang does not yet fully implement this
-feature.</p>
+<tt>nullptr</tt> is enabled.</p>
 
 <h4 id="cxx_override_control">C++0x <tt>override control</tt></h3>
 
index 6a9d4abef1b0bd3ef29bd0e988027ea088c3d0c7..01cd75fa8485202561ffadd1681b4d9a6c472be1 100644 (file)
@@ -571,7 +571,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
          //.Case("cxx_lambdas", false)
            .Case("cxx_noexcept", LangOpts.CPlusPlus0x)
-         //.Case("cxx_nullptr", false)
+           .Case("cxx_nullptr", LangOpts.CPlusPlus0x)
            .Case("cxx_override_control", LangOpts.CPlusPlus0x)
            .Case("cxx_range_for", LangOpts.CPlusPlus0x)
            .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
index e8dd56f66fb9bca623f505deaeedb23318ad2800..c3f330e371077fbb6489014f8c144cf85cac5ffe 100644 (file)
@@ -4705,6 +4705,10 @@ class BuiltinCandidateTypeSet  {
   /// were present in the candidate set.
   bool HasArithmeticOrEnumeralTypes;
 
+  /// \brief A flag indicating whether the nullptr type was present in the
+  /// candidate set.
+  bool HasNullPtrType;
+  
   /// Sema - The semantic analysis instance where we are building the
   /// candidate type set.
   Sema &SemaRef;
@@ -4723,6 +4727,7 @@ public:
   BuiltinCandidateTypeSet(Sema &SemaRef)
     : HasNonRecordTypes(false),
       HasArithmeticOrEnumeralTypes(false),
+      HasNullPtrType(false),
       SemaRef(SemaRef),
       Context(SemaRef.Context) { }
 
@@ -4755,6 +4760,7 @@ public:
 
   bool hasNonRecordTypes() { return HasNonRecordTypes; }
   bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
+  bool hasNullPtrType() const { return HasNullPtrType; }
 };
 
 /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
@@ -4915,6 +4921,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
     // extension.
     HasArithmeticOrEnumeralTypes = true;
     VectorTypes.insert(Ty);
+  } else if (Ty->isNullPtrType()) {
+    HasNullPtrType = true;
   } else if (AllowUserConversions && TyRec) {
     // No conversion functions in incomplete types.
     if (SemaRef.RequireCompleteType(Loc, Ty, 0))
@@ -5374,8 +5382,8 @@ public:
 
   // C++ [over.built]p15:
   //
-  //   For every pointer or enumeration type T, there exist
-  //   candidate operator functions of the form
+  //   For every T, where T is an enumeration type, a pointer type, or 
+  //   std::nullptr_t, there exist candidate operator functions of the form
   //
   //        bool       operator<(T, T);
   //        bool       operator>(T, T);
@@ -5460,6 +5468,17 @@ public:
         S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
                               CandidateSet);
       }
+      
+      if (CandidateTypes[ArgIdx].hasNullPtrType()) {
+        CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
+        if (AddedTypes.insert(NullPtrTy) &&
+            !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, 
+                                                             NullPtrTy))) {
+          QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
+          S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, 
+                                CandidateSet);
+        }
+      }
     }
   }
 
index f3392e41830155ae781ebc3f5c82cc427ff62645..8e7e1a12dd52dcd545da7c9bb4ff94b1712494ea 100644 (file)
@@ -602,8 +602,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
       T->isPointerType() ||
       //   -- reference to object or reference to function,
       T->isReferenceType() ||
-      //   -- pointer to member.
+      //   -- pointer to member,
       T->isMemberPointerType() ||
+      //   -- std::nullptr_t.
+      T->isNullPtrType() ||
       // If T is a dependent type, we can't do the check now, so we
       // assume that it is well-formed.
       T->isDependentType())
@@ -3756,10 +3758,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
   // from a template argument of type std::nullptr_t to a non-type
   // template parameter of type pointer to object, pointer to
   // function, or pointer-to-member, respectively.
-  if (ArgType->isNullPtrType() &&
-      (ParamType->isPointerType() || ParamType->isMemberPointerType())) {
-    Converted = TemplateArgument((NamedDecl *)0);
-    return Owned(Arg);
+  if (ArgType->isNullPtrType()) {
+    if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
+      Converted = TemplateArgument((NamedDecl *)0);
+      return Owned(Arg);
+    }
+    
+    if (ParamType->isNullPtrType()) {
+      llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true);
+      Converted = TemplateArgument(Zero, Context.NullPtrTy);
+      return Owned(Arg);
+    }
   }
 
   // Handle pointer-to-function, reference-to-function, and
@@ -4053,6 +4062,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
                                             Arg.getAsIntegral()->getBoolValue(),
                                             T, Loc));
 
+  if (T->isNullPtrType())
+    return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
+  
   // If this is an enum type that we're instantiating, we need to use an integer
   // type the same size as the enumerator.  We don't want to build an
   // IntegerLiteral with enum type.
index 57354f866ecb3a1f064996d87fb4cf4f456cb91a..ca5f868d9b056f1699b31b82511e1e8b8e78e4d7 100644 (file)
@@ -17,7 +17,7 @@ int has_nullptr();
 int no_nullptr();
 #endif
 
-// CHECK-0X: no_nullptr
+// CHECK-0X: has_nullptr
 // CHECK-NO-0X: no_nullptr
 
 
index 84c80aa286c2b82f9214ce1199e3782422be646c..d69af588a7d057e02abe8d3c0749746b267a7e65 100644 (file)
@@ -60,6 +60,10 @@ nullptr_t f(nullptr_t null)
 
   // You can reinterpret_cast nullptr to an integer.
   (void)reinterpret_cast<uintptr_t>(nullptr);
+  (void)reinterpret_cast<uintptr_t>(*pn);
+
+  int *ip = *pn;
+  if (*pn) { }
 
   // You can throw nullptr.
   throw nullptr;
@@ -104,3 +108,56 @@ namespace test3 {
     f("%p", nullptr);
   }
 }
+
+int array0[__is_scalar(nullptr_t)? 1 : -1];
+int array1[__is_pod(nullptr_t)? 1 : -1];
+int array2[sizeof(nullptr_t) == sizeof(void*)? 1 : -1];
+
+// FIXME: when we implement constexpr, this will be testable.
+#if 0
+int relational0[nullptr < nullptr? -1 : 1];
+int relational1[nullptr > nullptr? -1 : 1];
+int relational2[nullptr <= nullptr? 1 : -1];
+int relational3[nullptr >= nullptr? 1 : -1];
+int equality[nullptr == nullptr? 1 : -1];
+int inequality[nullptr != nullptr? -1 : 1];
+#endif
+
+namespace overloading {
+  int &f1(int*);
+  float &f1(bool);
+
+  void test_f1() {
+    int &ir = (f1)(nullptr);
+  }
+
+  struct ConvertsToNullPtr {
+    operator nullptr_t() const;
+  };
+
+  void test_conversion(ConvertsToNullPtr ctn) {
+    (void)(ctn == ctn);
+    (void)(ctn != ctn);
+    (void)(ctn <= ctn);
+    (void)(ctn >= ctn);
+    (void)(ctn < ctn);
+    (void)(ctn > ctn);
+  }
+}
+
+namespace templates {
+  template<typename T, nullptr_t Value>
+  struct X { 
+    X() { ptr = Value; }
+
+    T *ptr;
+  };
+  
+  X<int, nullptr> x;
+
+
+  template<int (*fp)(int), int* p, int A::* pmd, int (A::*pmf)(int)>
+  struct X2 {};
+  
+  X2<nullptr, nullptr, nullptr, nullptr> x2;
+}