]> granicus.if.org Git - clang/commitdiff
Give string literals const element typesin C++, and cope with the deprecated C++...
authorDouglas Gregor <dgregor@apple.com>
Fri, 12 Sep 2008 00:47:35 +0000 (00:47 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 12 Sep 2008 00:47:35 +0000 (00:47 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56137 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Type.h
lib/AST/Type.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/type-convert-construct.cpp

index 50ea6f083638453932a61527a6d27238284b978d..598f4a308156755944f159473112718a2255ed84 100644 (file)
@@ -302,6 +302,7 @@ public:
   bool isEnumeralType() const;
   bool isBooleanType() const;
   bool isCharType() const;
+  bool isWideCharType() const;
   bool isIntegralType() const;
   
   /// Floating point categories.
index 41cd828f01c2493b97f349425dad7b2fd3e476a1..2ecc357d95dc0cbe55b786d8ae5a752c79a47a9d 100644 (file)
@@ -498,6 +498,14 @@ bool Type::isCharType() const {
   return false;
 }
 
+bool Type::isWideCharType() const {
+  if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+    return BT->getKind() == BuiltinType::WChar;
+  if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType))
+    return ASQT->getBaseType()->isWideCharType();
+  return false;
+}
+
 /// isSignedIntegerType - Return true if this is an integer type that is
 /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
 /// an enum decl which has a signed representation, or a vector of signed
index f45e49ff018991e08be47e030ab72417fa00fb8e..e562547a8ee26291b34eb0635f0dc405b849571a 100644 (file)
@@ -890,6 +890,8 @@ private:
   // blcok pointer types.
   AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, 
                                                         QualType rhsType);
+
+  bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
   
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).
index 017e19df6c1e3f0b3e909ff46904ca32c081096a..f0765d538d699ec6dd91fbebe3d8e05d781049f1 100644 (file)
@@ -290,6 +290,10 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
   QualType StrTy = Context.CharTy;
   if (Literal.AnyWide) StrTy = Context.getWCharType();
   if (Literal.Pascal) StrTy = Context.UnsignedCharTy;
+
+  // A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
+  if (getLangOptions().CPlusPlus)
+    StrTy.addConst();
   
   // Get an array type for the string, according to C99 6.4.5.  This includes
   // the nul terminator character as well as the string length for pascal
@@ -3066,6 +3070,18 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
     DiagKind = diag::ext_typecheck_convert_pointer_void_func;
     break;
   case CompatiblePointerDiscardsQualifiers:
+    // If the qualifiers lost were because we were applying the
+    // (deprecated) C++ conversion from a string literal to a char*
+    // (or wchar_t*), then there was no error (C++ 4.2p2).  FIXME:
+    // Ideally, this check would be performed in
+    // CheckPointerTypesForAssignment. However, that would require a
+    // bit of refactoring (so that the second argument is an
+    // expression, rather than a type), which should be done as part
+    // of a larger effort to fix CheckPointerTypesForAssignment for
+    // C++ semantics.
+    if (getLangOptions().CPlusPlus &&
+        IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType))
+      return false;
     DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
     break;
   case IntToBlockPointer:
index a7e36c95fcdbf8fa4dc16f5d7dda3a194b4b5ce0..c8a21f7d53f58e0d701c80351cf02599de8d0306 100644 (file)
@@ -202,3 +202,34 @@ bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
                 Ty.getAsString(), CondExpr->getSourceRange());
   return false;
 }
+
+/// Helper function to determine whether this is the (deprecated) C++
+/// conversion from a string literal to a pointer to non-const char or
+/// non-const wchar_t (for narrow and wide string literals,
+/// respectively).
+bool 
+Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
+  // Look inside the implicit cast, if it exists.
+  if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From))
+    From = Cast->getSubExpr();
+
+  // A string literal (2.13.4) that is not a wide string literal can
+  // be converted to an rvalue of type "pointer to char"; a wide
+  // string literal can be converted to an rvalue of type "pointer
+  // to wchar_t" (C++ 4.2p2).
+  if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From))
+    if (const PointerType *ToPtrType = ToType->getAsPointerType())
+      if (const BuiltinType *ToPointeeType 
+          = ToPtrType->getPointeeType()->getAsBuiltinType()) {
+        // This conversion is considered only when there is an
+        // explicit appropriate pointer target type (C++ 4.2p2).
+        if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 &&
+            ((StrLit->isWide() && ToPointeeType->isWideCharType()) ||
+             (!StrLit->isWide() &&
+              (ToPointeeType->getKind() == BuiltinType::Char_U ||
+               ToPointeeType->getKind() == BuiltinType::Char_S))))
+          return true;
+      }
+
+  return false;
+}
index 64115f97ca9532d93428820fa653716ba75d7023..64191a29d93e1d1e7353e34670d176915c050c50 100644 (file)
@@ -10,4 +10,8 @@ void f() {
   typedef int T;
   int *p;
   bool v6 = T(0) == p;
+  char *str;
+  str = "a string";
+  wchar_t *wstr;
+  wstr = L"a wide string";
 }