aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Type.h1
-rw-r--r--lib/AST/Type.cpp8
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaExpr.cpp16
-rw-r--r--lib/Sema/SemaExprCXX.cpp31
-rw-r--r--test/SemaCXX/type-convert-construct.cpp4
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";
}