diff options
-rw-r--r-- | include/clang/AST/Type.h | 1 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 31 | ||||
-rw-r--r-- | test/SemaCXX/type-convert-construct.cpp | 4 |
6 files changed, 62 insertions, 0 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 50ea6f0836..598f4a3081 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -302,6 +302,7 @@ public: bool isEnumeralType() const; bool isBooleanType() const; bool isCharType() const; + bool isWideCharType() const; bool isIntegralType() const; /// Floating point categories. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 41cd828f01..2ecc357d95 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -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 diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f45e49ff01..e562547a8e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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). diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 017e19df6c..f0765d538d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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: diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index a7e36c95fc..c8a21f7d53 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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; +} diff --git a/test/SemaCXX/type-convert-construct.cpp b/test/SemaCXX/type-convert-construct.cpp index 64115f97ca..64191a29d9 100644 --- a/test/SemaCXX/type-convert-construct.cpp +++ b/test/SemaCXX/type-convert-construct.cpp @@ -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"; } |